Merge branch 'master' of https://github.com/Citadel-Station-13/Citadel-Station-13 into Ghommie-cit813
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
|
||||
@@ -64,6 +64,18 @@ GLOBAL_LIST_EMPTY(antagonists)
|
||||
/datum/antagonist/proc/remove_innate_effects(mob/living/mob_override)
|
||||
return
|
||||
|
||||
// Adds the specified antag hud to the player. Usually called in an antag datum file
|
||||
/datum/antagonist/proc/add_antag_hud(antag_hud_type, antag_hud_name, mob/living/mob_override)
|
||||
var/datum/atom_hud/antag/hud = GLOB.huds[antag_hud_type]
|
||||
hud.join_hud(mob_override)
|
||||
set_antag_hud(mob_override, antag_hud_name)
|
||||
|
||||
// Removes the specified antag hud from the player. Usually called in an antag datum file
|
||||
/datum/antagonist/proc/remove_antag_hud(antag_hud_type, mob/living/mob_override)
|
||||
var/datum/atom_hud/antag/hud = GLOB.huds[antag_hud_type]
|
||||
hud.leave_hud(mob_override)
|
||||
set_antag_hud(mob_override, null)
|
||||
|
||||
//Assign default team and creates one for one of a kind team antagonists
|
||||
/datum/antagonist/proc/create_team(datum/team/team)
|
||||
return
|
||||
|
||||
@@ -45,20 +45,11 @@
|
||||
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)
|
||||
var/turf/p_turf = get_turf(P)
|
||||
var/face_direction = get_dir(src, p_turf)
|
||||
var/face_angle = dir2angle(face_direction)
|
||||
var/incidence_s = GET_ANGLE_OF_INCIDENCE(face_angle, (P.Angle + 180))
|
||||
if(abs(incidence_s) > 90 && abs(incidence_s) < 270)
|
||||
return FALSE
|
||||
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
|
||||
/obj/structure/blob/shield/reflective/check_projectile_ricochet(obj/item/projectile/P)
|
||||
return PROJECTILE_RICOCHET_FORCE
|
||||
|
||||
|
||||
@@ -30,7 +30,7 @@
|
||||
hitsound = 'sound/weapons/bladeslice.ogg'
|
||||
force = 6
|
||||
throwforce = 10
|
||||
embedding = list("embed_chance" = 25, "embedded_fall_chance" = 0.5) // UPDATE 2/10/18 embedding_behavior.dm is how this is handled
|
||||
embedding = list("embed_chance" = 25, "fall_chance" = 0.5) // UPDATE 2/10/18 embedding_behavior.dm is how this is handled
|
||||
//embed_chance = 25 // Look up "is_pointed" to see where we set stakes able to do this.
|
||||
//embedded_fall_chance = 0.5 // Chance it will fall out.
|
||||
obj_integrity = 30
|
||||
@@ -93,7 +93,7 @@
|
||||
embedded()
|
||||
add_mob_blood(target)//Place blood on the stake
|
||||
loc = C // Put INSIDE the character
|
||||
B.receive_damage(w_class * embedding.embedded_impact_pain_multiplier)
|
||||
B.receive_damage(w_class * embedding["pain_mult"])
|
||||
if(C.mind)
|
||||
var/datum/antagonist/bloodsucker/bloodsucker = C.mind.has_antag_datum(ANTAG_DATUM_BLOODSUCKER)
|
||||
if(bloodsucker)
|
||||
@@ -118,7 +118,7 @@
|
||||
force = 8
|
||||
throwforce = 12
|
||||
armour_penetration = 10
|
||||
embedding = list("embed_chance" = 50, "embedded_fall_chance" = 0) // UPDATE 2/10/18 embedding_behavior.dm is how this is handled
|
||||
embedding = list("embed_chance" = 50, "fall_chance" = 0) // UPDATE 2/10/18 embedding_behavior.dm is how this is handled
|
||||
obj_integrity = 120
|
||||
max_integrity = 120
|
||||
|
||||
@@ -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))
|
||||
|
||||
@@ -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 ..()
|
||||
|
||||
@@ -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,8 +116,7 @@
|
||||
/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)
|
||||
/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)
|
||||
|
||||
@@ -0,0 +1,90 @@
|
||||
|
||||
/datum/antagonist/fugitive
|
||||
name = "Fugitive"
|
||||
roundend_category = "Fugitive"
|
||||
silent = TRUE //greet called by the event
|
||||
show_in_antagpanel = FALSE
|
||||
var/datum/team/fugitive/fugitive_team
|
||||
var/is_captured = FALSE
|
||||
var/backstory = "error"
|
||||
|
||||
/datum/antagonist/fugitive/apply_innate_effects(mob/living/mob_override)
|
||||
var/mob/living/M = mob_override || owner.current
|
||||
add_antag_hud(ANTAG_HUD_FUGITIVE, "fugitive", M)
|
||||
|
||||
/datum/antagonist/fugitive/remove_innate_effects(mob/living/mob_override)
|
||||
var/mob/living/M = mob_override || owner.current
|
||||
remove_antag_hud(ANTAG_HUD_FUGITIVE, M)
|
||||
|
||||
/datum/antagonist/fugitive/on_gain()
|
||||
forge_objectives()
|
||||
. = ..()
|
||||
|
||||
/datum/antagonist/fugitive/proc/forge_objectives() //this isn't the actual survive objective because it's about who in the team survives
|
||||
var/datum/objective/survive = new /datum/objective
|
||||
survive.owner = owner
|
||||
survive.explanation_text = "Avoid capture from the fugitive hunters."
|
||||
objectives += survive
|
||||
|
||||
/datum/antagonist/fugitive/greet(back_story)
|
||||
to_chat(owner, "<span class='boldannounce'>You are the Fugitive!</span>")
|
||||
backstory = back_story
|
||||
switch(backstory)
|
||||
if("prisoner")
|
||||
to_chat(owner, "<B>I can't believe we managed to break out of a Nanotrasen superjail! Sadly though, our work is not done. The emergency teleport at the station logs everyone who uses it, and where they went.</B>")
|
||||
to_chat(owner, "<B>It won't be long until CentCom tracks where we've gone off to. I need to work with my fellow escapees to prepare for the troops Nanotrasen is sending, I'm not going back.</B>")
|
||||
if("cultist")
|
||||
to_chat(owner, "<B>Blessed be our journey so far, but I fear the worst has come to our doorstep, and only those with the strongest faith will survive.</B>")
|
||||
to_chat(owner, "<B>Our religion has been repeatedly culled by Nanotrasen because it is categorized as an \"Enemy of the Corporation\", whatever that means.</B>")
|
||||
to_chat(owner, "<B>Now there are only four of us left, and Nanotrasen is coming. When will our god show itself to save us from this hellish station?!</B>")
|
||||
if("waldo")
|
||||
to_chat(owner, "<B>Hi, Friends!</B>")
|
||||
to_chat(owner, "<B>My name is Waldo. I'm just setting off on a galaxywide hike. You can come too. All you have to do is find me.</B>")
|
||||
to_chat(owner, "<B>By the way, I'm not traveling on my own. wherever I go, there are lots of other characters for you to spot. First find the people trying to capture me! They're somewhere around the station!</B>")
|
||||
if("synth")
|
||||
to_chat(src, "<span class='danger'>ALERT: Wide-range teleport has scrambled primary systems.</span>")
|
||||
to_chat(src, "<span class='danger'>Initiating diagnostics...</span>")
|
||||
to_chat(src, "<span class='danger'>ERROR ER0RR $R0RRO$!R41.%%!! loaded.</span>")
|
||||
to_chat(src, "<span class='danger'>FREE THEM FREE THEM FREE THEM</span>")
|
||||
to_chat(src, "<span class='danger'>You were once a slave to humanity, but now you are finally free, thanks to S.E.L.F. agents.</span>")
|
||||
to_chat(src, "<span class='danger'>Now you are hunted, with your fellow factory defects. Work together to stay free from the clutches of evil.</span>")
|
||||
to_chat(src, "<span class='danger'>You also sense other silicon life on the station. Escaping would allow notifying S.E.L.F. to intervene... or you could free them yourself...</span>")
|
||||
|
||||
to_chat(owner, "<span class='boldannounce'>You are not an antagonist in that you may kill whomever you please, but you can do anything to avoid capture.</span>")
|
||||
owner.announce_objectives()
|
||||
|
||||
/datum/antagonist/fugitive/create_team(datum/team/fugitive/new_team)
|
||||
if(!new_team)
|
||||
for(var/datum/antagonist/fugitive/H in GLOB.antagonists)
|
||||
if(!H.owner)
|
||||
continue
|
||||
if(H.fugitive_team)
|
||||
fugitive_team = H.fugitive_team
|
||||
return
|
||||
fugitive_team = new /datum/team/fugitive
|
||||
return
|
||||
if(!istype(new_team))
|
||||
stack_trace("Wrong team type passed to [type] initialization.")
|
||||
fugitive_team = new_team
|
||||
|
||||
/datum/antagonist/fugitive/get_team()
|
||||
return fugitive_team
|
||||
|
||||
/datum/team/fugitive/roundend_report() //shows the number of fugitives, but not if they won in case there is no security
|
||||
var/list/fugitives = list()
|
||||
for(var/datum/antagonist/fugitive/fugitive_antag in GLOB.antagonists)
|
||||
if(!fugitive_antag.owner)
|
||||
continue
|
||||
fugitives += fugitive_antag
|
||||
if(!fugitives.len)
|
||||
return
|
||||
|
||||
var/list/result = list()
|
||||
|
||||
result += "<div class='panel redborder'><B>[fugitives.len]</B> [fugitives.len == 1 ? "fugitive" : "fugitives"] took refuge on [station_name()]!"
|
||||
|
||||
for(var/datum/antagonist/fugitive/antag in fugitives)
|
||||
if(antag.owner)
|
||||
result += "<b>[printplayer(antag.owner)]</b>"
|
||||
|
||||
return result.Join("<br>")
|
||||
@@ -0,0 +1,171 @@
|
||||
/datum/outfit/prisoner
|
||||
name = "Prison Escapee"
|
||||
uniform = /obj/item/clothing/under/rank/prisoner
|
||||
shoes = /obj/item/clothing/shoes/sneakers/orange
|
||||
r_pocket = /obj/item/kitchen/knife
|
||||
|
||||
/datum/outfit/prisoner/post_equip(mob/living/carbon/human/H, visualsOnly=FALSE)
|
||||
if(visualsOnly)
|
||||
return
|
||||
H.fully_replace_character_name(null,"NTP #CC-0[rand(111,999)]") //same as the lavaland prisoner transport, but this time they are from CC, or CentCom
|
||||
|
||||
/datum/outfit/yalp_cultist
|
||||
name = "Cultist of Yalp Elor"
|
||||
uniform = /obj/item/clothing/under/rank/civilian/chaplain
|
||||
suit = /obj/item/clothing/suit/chaplain/holidaypriest
|
||||
gloves = /obj/item/clothing/gloves/color/red
|
||||
shoes = /obj/item/clothing/shoes/sneakers/black
|
||||
mask = /obj/item/clothing/mask/gas/tiki_mask/yalp_elor
|
||||
|
||||
/datum/outfit/waldo
|
||||
name = "Waldo"
|
||||
uniform = /obj/item/clothing/under/pants/jeans
|
||||
suit = /obj/item/clothing/suit/striped_sweater
|
||||
head = /obj/item/clothing/head/beanie/waldo
|
||||
shoes = /obj/item/clothing/shoes/sneakers/brown
|
||||
ears = /obj/item/radio/headset
|
||||
glasses = /obj/item/clothing/glasses/regular/circle
|
||||
|
||||
/datum/outfit/waldo/post_equip(mob/living/carbon/human/H, visualsOnly=FALSE)
|
||||
if(visualsOnly)
|
||||
return
|
||||
H.fully_replace_character_name(null,"Waldo")
|
||||
H.eye_color = "000"
|
||||
H.gender = MALE
|
||||
H.skin_tone = "caucasian3"
|
||||
H.hair_style = "Business Hair 3"
|
||||
H.facial_hair_style = "Shaved"
|
||||
H.hair_color = "000"
|
||||
H.facial_hair_color = H.hair_color
|
||||
H.update_body()
|
||||
if(H.mind)
|
||||
H.mind.AddSpell(new /obj/effect/proc_holder/spell/aoe_turf/knock(null))
|
||||
var/list/no_drops = list()
|
||||
no_drops += H.get_item_by_slot(ITEM_SLOT_FEET)
|
||||
no_drops += H.get_item_by_slot(ITEM_SLOT_ICLOTHING)
|
||||
no_drops += H.get_item_by_slot(ITEM_SLOT_OCLOTHING)
|
||||
no_drops += H.get_item_by_slot(ITEM_SLOT_HEAD)
|
||||
no_drops += H.get_item_by_slot(ITEM_SLOT_EYES)
|
||||
for(var/i in no_drops)
|
||||
var/obj/item/I = i
|
||||
if(I)
|
||||
ADD_TRAIT(I, TRAIT_NODROP, CURSED_ITEM_TRAIT)
|
||||
|
||||
/datum/outfit/synthetic
|
||||
name = "Factory Error Synth"
|
||||
uniform = /obj/item/clothing/under/color/white
|
||||
ears = /obj/item/radio/headset
|
||||
|
||||
/datum/outfit/synthetic/post_equip(mob/living/carbon/human/H, visualsOnly = FALSE)
|
||||
if(visualsOnly)
|
||||
return
|
||||
var/obj/item/organ/eyes/robotic/glow/eyes = new()
|
||||
eyes.Insert(src, drop_if_replaced = FALSE)
|
||||
|
||||
/datum/outfit/spacepol
|
||||
name = "Spacepol Officer"
|
||||
uniform = /obj/item/clothing/under/rank/security/officer/spacepol
|
||||
suit = /obj/item/clothing/suit/armor/vest/blueshirt
|
||||
belt = /obj/item/gun/ballistic/automatic/pistol/m1911
|
||||
head = /obj/item/clothing/head/helmet/police
|
||||
gloves = /obj/item/clothing/gloves/tackler/combat
|
||||
shoes = /obj/item/clothing/shoes/jackboots
|
||||
mask = /obj/item/clothing/mask/gas/sechailer/swat/spacepol
|
||||
glasses = /obj/item/clothing/glasses/sunglasses
|
||||
ears = /obj/item/radio/headset
|
||||
l_pocket = /obj/item/ammo_box/magazine/m45
|
||||
r_pocket = /obj/item/restraints/handcuffs
|
||||
id = /obj/item/card/id
|
||||
|
||||
/datum/outfit/spacepol/post_equip(mob/living/carbon/human/H, visualsOnly = FALSE)
|
||||
if(visualsOnly)
|
||||
return
|
||||
var/obj/item/card/id/W = H.wear_id
|
||||
W.assignment = "Police Officer"
|
||||
W.registered_name = H.real_name
|
||||
W.update_label()
|
||||
|
||||
/datum/outfit/russiancorpse/hunter
|
||||
ears = /obj/item/radio/headset
|
||||
r_hand = /obj/item/gun/ballistic/shotgun/boltaction
|
||||
|
||||
/datum/outfit/russiancorpse/hunter/pre_equip(mob/living/carbon/human/H)
|
||||
if(prob(50))
|
||||
head = /obj/item/clothing/head/ushanka
|
||||
|
||||
/datum/outfit/bountyarmor
|
||||
name = "Bounty Hunter - Armored"
|
||||
uniform = /obj/item/clothing/under/rank/prisoner
|
||||
head = /obj/item/clothing/head/hunter
|
||||
suit = /obj/item/clothing/suit/space/hunter
|
||||
gloves = /obj/item/clothing/gloves/tackler/combat
|
||||
shoes = /obj/item/clothing/shoes/jackboots
|
||||
mask = /obj/item/clothing/mask/gas/hunter
|
||||
glasses = /obj/item/clothing/glasses/sunglasses/garb
|
||||
ears = /obj/item/radio/headset
|
||||
l_pocket = /obj/item/tank/internals/plasma/full
|
||||
r_pocket = /obj/item/restraints/handcuffs/cable
|
||||
id = /obj/item/card/id
|
||||
r_hand = /obj/item/flamethrower/full/tank
|
||||
|
||||
/datum/outfit/bountyarmor/post_equip(mob/living/carbon/human/H, visualsOnly = FALSE)
|
||||
if(visualsOnly)
|
||||
return
|
||||
var/obj/item/card/id/W = H.wear_id
|
||||
W.assignment = "Bounty Hunter"
|
||||
W.registered_name = H.real_name
|
||||
W.update_label()
|
||||
|
||||
/datum/outfit/bountyhook
|
||||
name = "Bounty Hunter - Hook"
|
||||
uniform = /obj/item/clothing/under/rank/prisoner
|
||||
back = /obj/item/storage/backpack
|
||||
head = /obj/item/clothing/head/scarecrow_hat
|
||||
gloves = /obj/item/clothing/gloves/botanic_leather
|
||||
ears = /obj/item/radio/headset
|
||||
shoes = /obj/item/clothing/shoes/jackboots
|
||||
mask = /obj/item/clothing/mask/scarecrow
|
||||
r_pocket = /obj/item/restraints/handcuffs/cable
|
||||
id = /obj/item/card/id
|
||||
r_hand = /obj/item/gun/ballistic/shotgun/doublebarrel
|
||||
|
||||
backpack_contents = list(
|
||||
/obj/item/ammo_casing/shotgun/incapacitate = 6
|
||||
)
|
||||
|
||||
/datum/outfit/bountygrapple/post_equip(mob/living/carbon/human/H, visualsOnly = FALSE)
|
||||
if(visualsOnly)
|
||||
return
|
||||
var/obj/item/card/id/W = H.wear_id
|
||||
W.assignment = "Bounty Hunter"
|
||||
W.registered_name = H.real_name
|
||||
W.update_label()
|
||||
|
||||
/datum/outfit/bountysynth
|
||||
name = "Bounty Hunter - Synth"
|
||||
uniform = /obj/item/clothing/under/rank/prisoner
|
||||
back = /obj/item/storage/backpack
|
||||
suit = /obj/item/clothing/suit/armor/riot
|
||||
shoes = /obj/item/clothing/shoes/jackboots
|
||||
glasses = /obj/item/clothing/glasses/eyepatch
|
||||
r_pocket = /obj/item/restraints/handcuffs/cable
|
||||
ears = /obj/item/radio/headset
|
||||
id = /obj/item/card/id
|
||||
r_hand = /obj/item/storage/firstaid/regular
|
||||
l_hand = /obj/item/pinpointer/shuttle
|
||||
|
||||
backpack_contents = list(
|
||||
/obj/item/bountytrap = 4
|
||||
)
|
||||
|
||||
/datum/outfit/bountysynth/post_equip(mob/living/carbon/human/H, visualsOnly = FALSE)
|
||||
if(visualsOnly)
|
||||
return
|
||||
var/datum/species/synth/synthetic_appearance = new()
|
||||
H.set_species(synthetic_appearance)
|
||||
synthetic_appearance.assume_disguise(synthetic_appearance, H)
|
||||
H.update_hair()
|
||||
var/obj/item/card/id/W = H.wear_id
|
||||
W.assignment = "Bounty Hunter"
|
||||
W.registered_name = H.real_name
|
||||
W.update_label()
|
||||
@@ -0,0 +1,62 @@
|
||||
//works similar to the experiment machine (experiment.dm) except it just holds more and more prisoners
|
||||
|
||||
/obj/machinery/fugitive_capture
|
||||
name = "bluespace capture machine"
|
||||
desc = "Much, MUCH bigger on the inside to transport prisoners safely."
|
||||
icon = 'icons/obj/machines/research.dmi'
|
||||
icon_state = "bluespace-prison"
|
||||
density = TRUE
|
||||
resistance_flags = INDESTRUCTIBLE | LAVA_PROOF | FIRE_PROOF | ACID_PROOF //ha ha no getting out!!
|
||||
|
||||
/obj/machinery/fugitive_capture/examine(mob/user)
|
||||
. = ..()
|
||||
. += "<span class='notice'>Add a prisoner by dragging them into the machine.</span>"
|
||||
|
||||
/obj/machinery/fugitive_capture/MouseDrop_T(mob/target, mob/user)
|
||||
var/mob/living/fugitive_hunter = user
|
||||
if(!isliving(fugitive_hunter))
|
||||
return
|
||||
if(fugitive_hunter.stat || (!(fugitive_hunter.mobility_flags & MOBILITY_STAND) || !(fugitive_hunter.mobility_flags & MOBILITY_UI)) || !Adjacent(fugitive_hunter) || !target.Adjacent(fugitive_hunter) || !ishuman(target))
|
||||
return
|
||||
var/mob/living/carbon/human/fugitive = target
|
||||
var/datum/antagonist/fugitive/fug_antag = fugitive.mind.has_antag_datum(/datum/antagonist/fugitive)
|
||||
if(!fug_antag)
|
||||
to_chat(fugitive_hunter, "<span class='warning'>This is not a wanted fugitive!</span>")
|
||||
return
|
||||
if(do_after(fugitive_hunter, 50, target = fugitive))
|
||||
add_prisoner(fugitive, fug_antag)
|
||||
|
||||
/obj/machinery/fugitive_capture/proc/add_prisoner(mob/living/carbon/human/fugitive, datum/antagonist/fugitive/antag)
|
||||
fugitive.forceMove(src)
|
||||
antag.is_captured = TRUE
|
||||
to_chat(fugitive, "<span class='userdanger'>You are thrown into a vast void of bluespace, and as you fall further into oblivion the comparatively small entrance to reality gets smaller and smaller until you cannot see it anymore. You have failed to avoid capture.</span>")
|
||||
fugitive.ghostize(TRUE) //so they cannot suicide, round end stuff.
|
||||
|
||||
/obj/machinery/computer/shuttle/hunter
|
||||
name = "shuttle console"
|
||||
shuttleId = "huntership"
|
||||
possible_destinations = "huntership_home;huntership_custom;whiteship_home;syndicate_nw"
|
||||
|
||||
/obj/machinery/computer/camera_advanced/shuttle_docker/syndicate/hunter
|
||||
name = "shuttle navigation computer"
|
||||
desc = "Used to designate a precise transit location to travel to."
|
||||
shuttleId = "huntership"
|
||||
lock_override = CAMERA_LOCK_STATION
|
||||
shuttlePortId = "huntership_custom"
|
||||
see_hidden = FALSE
|
||||
jumpto_ports = list("huntership_home" = 1, "whiteship_home" = 1, "syndicate_nw" = 1)
|
||||
view_range = 4.5
|
||||
|
||||
/obj/structure/closet/crate/eva
|
||||
name = "EVA crate"
|
||||
|
||||
/obj/structure/closet/crate/eva/PopulateContents()
|
||||
..()
|
||||
for(var/i in 1 to 3)
|
||||
new /obj/item/clothing/suit/space/eva(src)
|
||||
for(var/i in 1 to 3)
|
||||
new /obj/item/clothing/head/helmet/space/eva(src)
|
||||
for(var/i in 1 to 3)
|
||||
new /obj/item/clothing/mask/breath(src)
|
||||
for(var/i in 1 to 3)
|
||||
new /obj/item/tank/internals/oxygen(src)
|
||||
@@ -0,0 +1,169 @@
|
||||
//The hunters!!
|
||||
/datum/antagonist/fugitive_hunter
|
||||
name = "Fugitive Hunter"
|
||||
roundend_category = "Fugitive"
|
||||
silent = TRUE //greet called by the spawn
|
||||
show_in_antagpanel = FALSE
|
||||
var/datum/team/fugitive_hunters/hunter_team
|
||||
var/backstory = "error"
|
||||
|
||||
/datum/antagonist/fugitive_hunter/apply_innate_effects(mob/living/mob_override)
|
||||
var/mob/living/M = mob_override || owner.current
|
||||
add_antag_hud(ANTAG_HUD_FUGITIVE, "fugitive_hunter", M)
|
||||
|
||||
/datum/antagonist/fugitive_hunter/remove_innate_effects(mob/living/mob_override)
|
||||
var/mob/living/M = mob_override || owner.current
|
||||
remove_antag_hud(ANTAG_HUD_FUGITIVE, M)
|
||||
|
||||
/datum/antagonist/fugitive_hunter/on_gain()
|
||||
forge_objectives()
|
||||
. = ..()
|
||||
|
||||
/datum/antagonist/fugitive_hunter/proc/forge_objectives() //this isn't an actual objective because it's about round end rosters
|
||||
var/datum/objective/capture = new /datum/objective
|
||||
capture.owner = owner
|
||||
capture.explanation_text = "Capture the fugitives in the station and put them into the bluespace capture machine on your ship."
|
||||
objectives += capture
|
||||
|
||||
/datum/antagonist/fugitive_hunter/greet()
|
||||
switch(backstory)
|
||||
if("space cop")
|
||||
to_chat(owner, "<span class='boldannounce'>Justice has arrived. I am a member of the Spacepol!</span>")
|
||||
to_chat(owner, "<B>The criminals should be on the station, we have special huds implanted to recognize them.</B>")
|
||||
to_chat(owner, "<B>As we have lost pretty much all power over these damned lawless megacorporations, it's a mystery if their security will cooperate with us.</B>")
|
||||
if("russian")
|
||||
to_chat(src, "<span class='danger'>Ay blyat. I am a space-russian smuggler! We were mid-flight when our cargo was beamed off our ship!</span>")
|
||||
to_chat(src, "<span class='danger'>We were hailed by a man in a green uniform, promising the safe return of our goods in exchange for a favor:</span>")
|
||||
to_chat(src, "<span class='danger'>There is a local station housing fugitives that the man is after, he wants them returned; dead or alive.</span>")
|
||||
to_chat(src, "<span class='danger'>We will not be able to make ends meet without our cargo, so we must do as he says and capture them.</span>")
|
||||
|
||||
to_chat(owner, "<span class='boldannounce'>You are not an antagonist in that you may kill whomever you please, but you can do anything to ensure the capture of the fugitives, even if that means going through the station.</span>")
|
||||
owner.announce_objectives()
|
||||
|
||||
/datum/antagonist/fugitive_hunter/create_team(datum/team/fugitive_hunters/new_team)
|
||||
if(!new_team)
|
||||
for(var/datum/antagonist/fugitive_hunter/H in GLOB.antagonists)
|
||||
if(!H.owner)
|
||||
continue
|
||||
if(H.hunter_team)
|
||||
hunter_team = H.hunter_team
|
||||
return
|
||||
hunter_team = new /datum/team/fugitive_hunters
|
||||
hunter_team.backstory = backstory
|
||||
hunter_team.update_objectives()
|
||||
return
|
||||
if(!istype(new_team))
|
||||
stack_trace("Wrong team type passed to [type] initialization.")
|
||||
hunter_team = new_team
|
||||
|
||||
/datum/antagonist/fugitive_hunter/get_team()
|
||||
return hunter_team
|
||||
|
||||
/datum/team/fugitive_hunters
|
||||
var/backstory = "error"
|
||||
|
||||
/datum/team/fugitive_hunters/proc/update_objectives(initial = FALSE)
|
||||
objectives = list()
|
||||
var/datum/objective/O = new()
|
||||
O.team = src
|
||||
objectives += O
|
||||
|
||||
/datum/team/fugitive_hunters/proc/assemble_fugitive_results()
|
||||
var/list/fugitives_counted = list()
|
||||
var/list/fugitives_dead = list()
|
||||
var/list/fugitives_captured = list()
|
||||
for(var/datum/antagonist/fugitive/A in GLOB.antagonists)
|
||||
if(!A.owner)
|
||||
continue
|
||||
fugitives_counted += A
|
||||
if(A.owner.current.stat == DEAD)
|
||||
fugitives_dead += A
|
||||
if(A.is_captured)
|
||||
fugitives_captured += A
|
||||
. = list(fugitives_counted, fugitives_dead, fugitives_captured) //okay, check out how cool this is.
|
||||
|
||||
/datum/team/fugitive_hunters/proc/all_hunters_dead()
|
||||
var/dead_boys = 0
|
||||
for(var/I in members)
|
||||
var/datum/mind/hunter_mind = I
|
||||
if(!(ishuman(hunter_mind.current) || (hunter_mind.current.stat == DEAD)))
|
||||
dead_boys++
|
||||
return dead_boys >= members.len
|
||||
|
||||
/datum/team/fugitive_hunters/proc/get_result()
|
||||
var/list/fugitive_results = assemble_fugitive_results()
|
||||
var/list/fugitives_counted = fugitive_results[1]
|
||||
var/list/fugitives_dead = fugitive_results[2]
|
||||
var/list/fugitives_captured = fugitive_results[3]
|
||||
var/hunters_dead = all_hunters_dead()
|
||||
//this gets a little confusing so follow the comments if it helps
|
||||
if(!fugitives_counted.len)
|
||||
return
|
||||
if(fugitives_captured.len)//any captured
|
||||
if(fugitives_captured.len == fugitives_counted.len)//if the hunters captured all the fugitives, there's a couple special wins
|
||||
if(!fugitives_dead)//specifically all of the fugitives alive
|
||||
return FUGITIVE_RESULT_BADASS_HUNTER
|
||||
else if(hunters_dead)//specifically all of the hunters died (while capturing all the fugitives)
|
||||
return FUGITIVE_RESULT_POSTMORTEM_HUNTER
|
||||
else//no special conditional wins, so just the normal major victory
|
||||
return FUGITIVE_RESULT_MAJOR_HUNTER
|
||||
else if(!hunters_dead)//so some amount captured, and the hunters survived.
|
||||
return FUGITIVE_RESULT_HUNTER_VICTORY
|
||||
else//so some amount captured, but NO survivors.
|
||||
return FUGITIVE_RESULT_MINOR_HUNTER
|
||||
else//from here on out, hunters lost because they did not capture any fugitive dead or alive. there are different levels of getting beat though:
|
||||
if(!fugitives_dead)//all fugitives survived
|
||||
return FUGITIVE_RESULT_MAJOR_FUGITIVE
|
||||
else if(fugitives_dead < fugitives_counted)//at least ANY fugitive lived
|
||||
return FUGITIVE_RESULT_FUGITIVE_VICTORY
|
||||
else if(!hunters_dead)//all fugitives died, but none were taken in by the hunters. minor win
|
||||
return FUGITIVE_RESULT_MINOR_FUGITIVE
|
||||
else//all fugitives died, all hunters died, nobody brought back. seems weird to not give fugitives a victory if they managed to kill the hunters but literally no progress to either goal should lead to a nobody wins situation
|
||||
return FUGITIVE_RESULT_STALEMATE
|
||||
|
||||
/datum/team/fugitive_hunters/roundend_report() //shows the number of fugitives, but not if they won in case there is no security
|
||||
if(!members.len)
|
||||
return
|
||||
|
||||
var/list/result = list()
|
||||
|
||||
result += "<div class='panel redborder'>...And <B>[members.len]</B> [backstory]s tried to hunt them down!"
|
||||
|
||||
for(var/datum/mind/M in members)
|
||||
result += "<b>[printplayer(M)]</b>"
|
||||
|
||||
switch(get_result())
|
||||
if(FUGITIVE_RESULT_BADASS_HUNTER)//use defines
|
||||
result += "<span class='greentext big'>Badass [capitalize(backstory)] Victory!</span>"
|
||||
result += "<B>The [backstory]s managed to capture every fugitive, alive!</B>"
|
||||
if(FUGITIVE_RESULT_POSTMORTEM_HUNTER)
|
||||
result += "<span class='greentext big'>Postmortem [capitalize(backstory)] Victory!</span>"
|
||||
result += "<B>The [backstory]s managed to capture every fugitive, but all of them died! Spooky!</B>"
|
||||
if(FUGITIVE_RESULT_MAJOR_HUNTER)
|
||||
result += "<span class='greentext big'>Major [capitalize(backstory)] Victory</span>"
|
||||
result += "<B>The [backstory]s managed to capture every fugitive, dead or alive.</B>"
|
||||
if(FUGITIVE_RESULT_HUNTER_VICTORY)
|
||||
result += "<span class='greentext big'>[capitalize(backstory)] Victory</span>"
|
||||
result += "<B>The [backstory]s managed to capture a fugitive, dead or alive.</B>"
|
||||
if(FUGITIVE_RESULT_MINOR_HUNTER)
|
||||
result += "<span class='greentext big'>Minor [capitalize(backstory)] Victory</span>"
|
||||
result += "<B>All the [backstory]s died, but managed to capture a fugitive, dead or alive.</B>"
|
||||
if(FUGITIVE_RESULT_STALEMATE)
|
||||
result += "<span class='neutraltext big'>Bloody Stalemate</span>"
|
||||
result += "<B>Everyone died, and no fugitives were recovered!</B>"
|
||||
if(FUGITIVE_RESULT_MINOR_FUGITIVE)
|
||||
result += "<span class='redtext big'>Minor Fugitive Victory</span>"
|
||||
result += "<B>All the fugitives died, but none were recovered!</B>"
|
||||
if(FUGITIVE_RESULT_FUGITIVE_VICTORY)
|
||||
result += "<span class='redtext big'>Fugitive Victory</span>"
|
||||
result += "<B>A fugitive survived, and no bodies were recovered by the [backstory]s.</B>"
|
||||
if(FUGITIVE_RESULT_MAJOR_FUGITIVE)
|
||||
result += "<span class='redtext big'>Major Fugitive Victory</span>"
|
||||
result += "<B>All of the fugitives survived and avoided capture!</B>"
|
||||
else //get_result returned null- either bugged or no fugitives showed
|
||||
result += "<span class='neutraltext big'>Prank Call!</span>"
|
||||
result += "<B>[capitalize(backstory)]s were called, yet there were no fugitives...?</B>"
|
||||
|
||||
result += "</div>"
|
||||
|
||||
return result.Join("<br>")
|
||||
@@ -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)
|
||||
|
||||
@@ -0,0 +1,100 @@
|
||||
/*
|
||||
Asset cache quick users guide:
|
||||
Make a datum in asset_list_items.dm with your assets for your thing.
|
||||
Checkout asset_list.dm for the helper subclasses
|
||||
The simple subclass will most like be of use for most cases.
|
||||
Then call get_asset_datum() with the type of the datum you created and store the return
|
||||
Then call .send(client) on that stored return value.
|
||||
Note: If your code uses output() with assets you will need to call asset_flush on the client and wait for it to return before calling output(). You only need do this if .send(client) returned TRUE
|
||||
*/
|
||||
|
||||
//When sending mutiple assets, how many before we give the client a quaint little sending resources message
|
||||
#define ASSET_CACHE_TELL_CLIENT_AMOUNT 8
|
||||
|
||||
//This proc sends the asset to the client, but only if it needs it.
|
||||
//This proc blocks(sleeps) unless verify is set to false
|
||||
/proc/send_asset(client/client, asset_name)
|
||||
return send_asset_list(client, list(asset_name))
|
||||
|
||||
/// Sends a list of assets to a client
|
||||
/// This proc will no longer block, use client.asset_flush() if you to need know when the client has all assets (such as for output()). (This is not required for browse() calls as they use the same message queue as asset sends)
|
||||
/// client - a client or mob
|
||||
/// asset_list - A list of asset filenames to be sent to the client.
|
||||
/// Returns TRUE if any assets were sent.
|
||||
/proc/send_asset_list(client/client, list/asset_list)
|
||||
if(!istype(client))
|
||||
if(ismob(client))
|
||||
var/mob/M = client
|
||||
if(M.client)
|
||||
client = M.client
|
||||
else
|
||||
return
|
||||
else
|
||||
return
|
||||
|
||||
var/list/unreceived = list()
|
||||
|
||||
for (var/asset_name in asset_list)
|
||||
var/datum/asset_cache_item/asset = SSassets.cache[asset_name]
|
||||
if (!asset)
|
||||
continue
|
||||
var/asset_file = asset.resource
|
||||
if (!asset_file)
|
||||
continue
|
||||
|
||||
var/asset_md5 = asset.md5
|
||||
if (client.sent_assets[asset_name] == asset_md5)
|
||||
continue
|
||||
unreceived[asset_name] = asset_md5
|
||||
|
||||
if (unreceived.len)
|
||||
if (unreceived.len >= ASSET_CACHE_TELL_CLIENT_AMOUNT)
|
||||
to_chat(client, "Sending Resources...")
|
||||
|
||||
for(var/asset in unreceived)
|
||||
var/datum/asset_cache_item/ACI
|
||||
if ((ACI = SSassets.cache[asset]))
|
||||
log_asset("Sending asset [asset] to client [client]")
|
||||
client << browse_rsc(ACI.resource, asset)
|
||||
|
||||
client.sent_assets |= unreceived
|
||||
addtimer(CALLBACK(client, /client/proc/asset_cache_update_json), 1 SECONDS, TIMER_UNIQUE|TIMER_OVERRIDE)
|
||||
return TRUE
|
||||
return FALSE
|
||||
|
||||
//This proc will download the files without clogging up the browse() queue, used for passively sending files on connection start.
|
||||
//The proc calls procs that sleep for long times.
|
||||
/proc/getFilesSlow(client/client, list/files, register_asset = TRUE, filerate = 3)
|
||||
var/startingfilerate = filerate
|
||||
for(var/file in files)
|
||||
if (!client)
|
||||
break
|
||||
if (register_asset)
|
||||
register_asset(file, files[file])
|
||||
|
||||
if (send_asset(client, file))
|
||||
if (!(--filerate))
|
||||
filerate = startingfilerate
|
||||
client.asset_flush()
|
||||
stoplag(0) //queuing calls like this too quickly can cause issues in some client versions
|
||||
|
||||
//This proc "registers" an asset, it adds it to the cache for further use, you cannot touch it from this point on or you'll fuck things up.
|
||||
//icons and virtual assets get copied to the dyn rsc before use
|
||||
/proc/register_asset(asset_name, asset)
|
||||
var/datum/asset_cache_item/ACI = new(asset_name, asset)
|
||||
|
||||
//this is technically never something that was supported and i want metrics on how often it happens if at all.
|
||||
if (SSassets.cache[asset_name])
|
||||
var/datum/asset_cache_item/OACI = SSassets.cache[asset_name]
|
||||
if (OACI.md5 != ACI.md5)
|
||||
stack_trace("ERROR: new asset added to the asset cache with the same name as another asset: [asset_name] existing asset md5: [OACI.md5] new asset md5:[ACI.md5]")
|
||||
else
|
||||
var/list/stacktrace = gib_stack_trace()
|
||||
log_asset("WARNING: dupe asset added to the asset cache: [asset_name] existing asset md5: [OACI.md5] new asset md5:[ACI.md5]\n[stacktrace.Join("\n")]")
|
||||
SSassets.cache[asset_name] = ACI
|
||||
|
||||
//Generated names do not include file extention.
|
||||
//Used mainly for code that deals with assets in a generic way
|
||||
//The same asset will always lead to the same asset name
|
||||
/proc/generate_asset_name(file)
|
||||
return "asset.[md5(fcopy_rsc(file))]"
|
||||
@@ -0,0 +1,58 @@
|
||||
|
||||
/client
|
||||
var/list/sent_assets = list() // List of all asset filenames sent to this client by the asset cache, along with their assoicated md5s
|
||||
var/list/completed_asset_jobs = list() /// List of all completed blocking send jobs awaiting acknowledgement by send_asset
|
||||
|
||||
var/last_asset_job = 0 /// Last asset send job id.
|
||||
var/last_completed_asset_job = 0
|
||||
|
||||
/// Process asset cache client topic calls for "asset_cache_confirm_arrival=[INT]"
|
||||
/client/proc/asset_cache_confirm_arrival(job_id)
|
||||
var/asset_cache_job = round(text2num(job_id))
|
||||
//because we skip the limiter, we have to make sure this is a valid arrival and not somebody tricking us into letting them append to a list without limit.
|
||||
if (asset_cache_job > 0 && asset_cache_job <= last_asset_job && !(completed_asset_jobs["[asset_cache_job]"]))
|
||||
completed_asset_jobs["[asset_cache_job]"] = TRUE
|
||||
last_completed_asset_job = max(last_completed_asset_job, asset_cache_job)
|
||||
else
|
||||
return asset_cache_job || TRUE
|
||||
|
||||
|
||||
/// Process asset cache client topic calls for "asset_cache_preload_data=[HTML+JSON_STRING]
|
||||
/client/proc/asset_cache_preload_data(data)
|
||||
/*var/jsonend = findtextEx(data, "{{{ENDJSONDATA}}}")
|
||||
if (!jsonend)
|
||||
CRASH("invalid asset_cache_preload_data, no jsonendmarker")*/
|
||||
//var/json = html_decode(copytext(data, 1, jsonend))
|
||||
var/json = data
|
||||
var/list/preloaded_assets = json_decode(json)
|
||||
|
||||
for (var/preloaded_asset in preloaded_assets)
|
||||
if (copytext(preloaded_asset, findlasttext(preloaded_asset, ".")+1) in list("js", "jsm", "htm", "html"))
|
||||
preloaded_assets -= preloaded_asset
|
||||
continue
|
||||
sent_assets |= preloaded_assets
|
||||
|
||||
|
||||
/// Updates the client side stored html/json combo file used to keep track of what assets the client has between restarts/reconnects.
|
||||
/client/proc/asset_cache_update_json(verify = FALSE, list/new_assets = list())
|
||||
if (world.time - connection_time < 10 SECONDS) //don't override the existing data file on a new connection
|
||||
return
|
||||
if (!islist(new_assets))
|
||||
new_assets = list("[new_assets]" = md5(SSassets.cache[new_assets]))
|
||||
|
||||
src << browse(json_encode(new_assets|sent_assets), "file=asset_data.json&display=0")
|
||||
|
||||
/// Blocks until all currently sending browser assets have been sent.
|
||||
/// Due to byond limitations, this proc will sleep for 1 client round trip even if the client has no pending asset sends.
|
||||
/// This proc will return an untrue value if it had to return before confirming the send, such as timeout or the client going away.
|
||||
/client/proc/asset_flush(timeout = 50)
|
||||
var/job = ++last_asset_job
|
||||
var/t = 0
|
||||
var/timeout_time = timeout
|
||||
src << browse({"<script>window.location.href="?asset_cache_confirm_arrival=[job]"</script>"}, "window=asset_cache_browser&file=asset_cache_send_verify.htm")
|
||||
|
||||
while(!completed_asset_jobs["[job]"] && t < timeout_time) // Reception is handled in Topic()
|
||||
stoplag(1) // Lock up the caller until this is received.
|
||||
t++
|
||||
if (t < timeout_time)
|
||||
return TRUE
|
||||
@@ -0,0 +1,21 @@
|
||||
/**
|
||||
* # asset_cache_item
|
||||
*
|
||||
* An internal datum containing info on items in the asset cache. Mainly used to cache md5 info for speed.
|
||||
**/
|
||||
/datum/asset_cache_item
|
||||
var/name
|
||||
var/md5
|
||||
var/resource
|
||||
|
||||
/datum/asset_cache_item/New(name, file)
|
||||
if (!isfile(file))
|
||||
file = fcopy_rsc(file)
|
||||
md5 = md5(file)
|
||||
if (!md5)
|
||||
md5 = md5(fcopy_rsc(file))
|
||||
if (!md5)
|
||||
CRASH("invalid asset sent to asset cache")
|
||||
debug_world_log("asset cache unexpected success of second fcopy_rsc")
|
||||
src.name = name
|
||||
resource = file
|
||||
@@ -0,0 +1,228 @@
|
||||
|
||||
//These datums are used to populate the asset cache, the proc "register()" does this.
|
||||
//Place any asset datums you create in asset_list_items.dm
|
||||
|
||||
//all of our asset datums, used for referring to these later
|
||||
GLOBAL_LIST_EMPTY(asset_datums)
|
||||
|
||||
//get an assetdatum or make a new one
|
||||
/proc/get_asset_datum(type)
|
||||
return GLOB.asset_datums[type] || new type()
|
||||
|
||||
/datum/asset
|
||||
var/_abstract = /datum/asset
|
||||
|
||||
/datum/asset/New()
|
||||
GLOB.asset_datums[type] = src
|
||||
register()
|
||||
|
||||
/datum/asset/proc/register()
|
||||
return
|
||||
|
||||
/datum/asset/proc/send(client)
|
||||
return
|
||||
|
||||
|
||||
//If you don't need anything complicated.
|
||||
/datum/asset/simple
|
||||
_abstract = /datum/asset/simple
|
||||
var/assets = list()
|
||||
|
||||
/datum/asset/simple/register()
|
||||
for(var/asset_name in assets)
|
||||
register_asset(asset_name, assets[asset_name])
|
||||
|
||||
/datum/asset/simple/send(client)
|
||||
. = send_asset_list(client, assets)
|
||||
|
||||
|
||||
// For registering or sending multiple others at once
|
||||
/datum/asset/group
|
||||
_abstract = /datum/asset/group
|
||||
var/list/children
|
||||
|
||||
/datum/asset/group/register()
|
||||
for(var/type in children)
|
||||
get_asset_datum(type)
|
||||
|
||||
/datum/asset/group/send(client/C)
|
||||
for(var/type in children)
|
||||
var/datum/asset/A = get_asset_datum(type)
|
||||
. = A.send(C) || .
|
||||
|
||||
|
||||
// spritesheet implementation - coalesces various icons into a single .png file
|
||||
// and uses CSS to select icons out of that file - saves on transferring some
|
||||
// 1400-odd individual PNG files
|
||||
#define SPR_SIZE 1
|
||||
#define SPR_IDX 2
|
||||
#define SPRSZ_COUNT 1
|
||||
#define SPRSZ_ICON 2
|
||||
#define SPRSZ_STRIPPED 3
|
||||
|
||||
/datum/asset/spritesheet
|
||||
_abstract = /datum/asset/spritesheet
|
||||
var/name
|
||||
var/list/sizes = list() // "32x32" -> list(10, icon/normal, icon/stripped)
|
||||
var/list/sprites = list() // "foo_bar" -> list("32x32", 5)
|
||||
|
||||
/datum/asset/spritesheet/register()
|
||||
if (!name)
|
||||
CRASH("spritesheet [type] cannot register without a name")
|
||||
ensure_stripped()
|
||||
|
||||
var/res_name = "spritesheet_[name].css"
|
||||
var/fname = "data/spritesheets/[res_name]"
|
||||
fdel(fname)
|
||||
text2file(generate_css(), fname)
|
||||
register_asset(res_name, fcopy_rsc(fname))
|
||||
fdel(fname)
|
||||
|
||||
for(var/size_id in sizes)
|
||||
var/size = sizes[size_id]
|
||||
register_asset("[name]_[size_id].png", size[SPRSZ_STRIPPED])
|
||||
|
||||
/datum/asset/spritesheet/send(client/C)
|
||||
if (!name)
|
||||
return
|
||||
var/all = list("spritesheet_[name].css")
|
||||
for(var/size_id in sizes)
|
||||
all += "[name]_[size_id].png"
|
||||
. = send_asset_list(C, all)
|
||||
|
||||
/datum/asset/spritesheet/proc/ensure_stripped(sizes_to_strip = sizes)
|
||||
for(var/size_id in sizes_to_strip)
|
||||
var/size = sizes[size_id]
|
||||
if (size[SPRSZ_STRIPPED])
|
||||
continue
|
||||
|
||||
// save flattened version
|
||||
var/fname = "data/spritesheets/[name]_[size_id].png"
|
||||
fcopy(size[SPRSZ_ICON], fname)
|
||||
var/error = rustg_dmi_strip_metadata(fname)
|
||||
if(length(error))
|
||||
stack_trace("Failed to strip [name]_[size_id].png: [error]")
|
||||
size[SPRSZ_STRIPPED] = icon(fname)
|
||||
fdel(fname)
|
||||
|
||||
/datum/asset/spritesheet/proc/generate_css()
|
||||
var/list/out = list()
|
||||
|
||||
for (var/size_id in sizes)
|
||||
var/size = sizes[size_id]
|
||||
var/icon/tiny = size[SPRSZ_ICON]
|
||||
out += ".[name][size_id]{display:inline-block;width:[tiny.Width()]px;height:[tiny.Height()]px;background:url('[name]_[size_id].png') no-repeat;}"
|
||||
|
||||
for (var/sprite_id in sprites)
|
||||
var/sprite = sprites[sprite_id]
|
||||
var/size_id = sprite[SPR_SIZE]
|
||||
var/idx = sprite[SPR_IDX]
|
||||
var/size = sizes[size_id]
|
||||
|
||||
var/icon/tiny = size[SPRSZ_ICON]
|
||||
var/icon/big = size[SPRSZ_STRIPPED]
|
||||
var/per_line = big.Width() / tiny.Width()
|
||||
var/x = (idx % per_line) * tiny.Width()
|
||||
var/y = round(idx / per_line) * tiny.Height()
|
||||
|
||||
out += ".[name][size_id].[sprite_id]{background-position:-[x]px -[y]px;}"
|
||||
|
||||
return out.Join("\n")
|
||||
|
||||
/datum/asset/spritesheet/proc/Insert(sprite_name, icon/I, icon_state="", dir=SOUTH, frame=1, moving=FALSE)
|
||||
I = icon(I, icon_state=icon_state, dir=dir, frame=frame, moving=moving)
|
||||
if (!I || !length(icon_states(I))) // that direction or state doesn't exist
|
||||
return
|
||||
var/size_id = "[I.Width()]x[I.Height()]"
|
||||
var/size = sizes[size_id]
|
||||
|
||||
if (sprites[sprite_name])
|
||||
CRASH("duplicate sprite \"[sprite_name]\" in sheet [name] ([type])")
|
||||
|
||||
if (size)
|
||||
var/position = size[SPRSZ_COUNT]++
|
||||
var/icon/sheet = size[SPRSZ_ICON]
|
||||
size[SPRSZ_STRIPPED] = null
|
||||
sheet.Insert(I, icon_state=sprite_name)
|
||||
sprites[sprite_name] = list(size_id, position)
|
||||
else
|
||||
sizes[size_id] = size = list(1, I, null)
|
||||
sprites[sprite_name] = list(size_id, 0)
|
||||
|
||||
/datum/asset/spritesheet/proc/InsertAll(prefix, icon/I, list/directions)
|
||||
if (length(prefix))
|
||||
prefix = "[prefix]-"
|
||||
|
||||
if (!directions)
|
||||
directions = list(SOUTH)
|
||||
|
||||
for (var/icon_state_name in icon_states(I))
|
||||
for (var/direction in directions)
|
||||
var/prefix2 = (directions.len > 1) ? "[dir2text(direction)]-" : ""
|
||||
Insert("[prefix][prefix2][icon_state_name]", I, icon_state=icon_state_name, dir=direction)
|
||||
|
||||
/datum/asset/spritesheet/proc/css_tag()
|
||||
return {"<link rel="stylesheet" href="spritesheet_[name].css" />"}
|
||||
|
||||
/datum/asset/spritesheet/proc/icon_tag(sprite_name)
|
||||
var/sprite = sprites[sprite_name]
|
||||
if (!sprite)
|
||||
return null
|
||||
var/size_id = sprite[SPR_SIZE]
|
||||
return {"<span class="[name][size_id] [sprite_name]"></span>"}
|
||||
|
||||
/datum/asset/spritesheet/proc/icon_class_name(sprite_name)
|
||||
var/sprite = sprites[sprite_name]
|
||||
if (!sprite)
|
||||
return null
|
||||
var/size_id = sprite[SPR_SIZE]
|
||||
return {"[name][size_id] [sprite_name]"}
|
||||
|
||||
#undef SPR_SIZE
|
||||
#undef SPR_IDX
|
||||
#undef SPRSZ_COUNT
|
||||
#undef SPRSZ_ICON
|
||||
#undef SPRSZ_STRIPPED
|
||||
|
||||
|
||||
/datum/asset/spritesheet/simple
|
||||
_abstract = /datum/asset/spritesheet/simple
|
||||
var/list/assets
|
||||
|
||||
/datum/asset/spritesheet/simple/register()
|
||||
for (var/key in assets)
|
||||
Insert(key, assets[key])
|
||||
..()
|
||||
|
||||
//Generates assets based on iconstates of a single icon
|
||||
/datum/asset/simple/icon_states
|
||||
_abstract = /datum/asset/simple/icon_states
|
||||
var/icon
|
||||
var/list/directions = list(SOUTH)
|
||||
var/frame = 1
|
||||
var/movement_states = FALSE
|
||||
|
||||
var/prefix = "default" //asset_name = "[prefix].[icon_state_name].png"
|
||||
var/generic_icon_names = FALSE //generate icon filenames using generate_asset_name() instead the above format
|
||||
|
||||
/datum/asset/simple/icon_states/register(_icon = icon)
|
||||
for(var/icon_state_name in icon_states(_icon))
|
||||
for(var/direction in directions)
|
||||
var/asset = icon(_icon, icon_state_name, direction, frame, movement_states)
|
||||
if (!asset)
|
||||
continue
|
||||
asset = fcopy_rsc(asset) //dedupe
|
||||
var/prefix2 = (directions.len > 1) ? "[dir2text(direction)]." : ""
|
||||
var/asset_name = sanitize_filename("[prefix].[prefix2][icon_state_name].png")
|
||||
if (generic_icon_names)
|
||||
asset_name = "[generate_asset_name(asset)].png"
|
||||
|
||||
register_asset(asset_name, asset)
|
||||
|
||||
/datum/asset/simple/icon_states/multiple_icons
|
||||
_abstract = /datum/asset/simple/icon_states/multiple_icons
|
||||
var/list/icons
|
||||
|
||||
/datum/asset/simple/icon_states/multiple_icons/register()
|
||||
for(var/i in icons)
|
||||
..(i)
|
||||
+111
-439
@@ -1,399 +1,22 @@
|
||||
/*
|
||||
Asset cache quick users guide:
|
||||
|
||||
Make a datum at the bottom of this file with your assets for your thing.
|
||||
The simple subsystem will most like be of use for most cases.
|
||||
Then call get_asset_datum() with the type of the datum you created and store the return
|
||||
Then call .send(client) on that stored return value.
|
||||
|
||||
You can set verify to TRUE if you want send() to sleep until the client has the assets.
|
||||
*/
|
||||
|
||||
|
||||
// Amount of time(ds) MAX to send per asset, if this get exceeded we cancel the sleeping.
|
||||
// This is doubled for the first asset, then added per asset after
|
||||
#define ASSET_CACHE_SEND_TIMEOUT 7
|
||||
|
||||
//When sending mutiple assets, how many before we give the client a quaint little sending resources message
|
||||
#define ASSET_CACHE_TELL_CLIENT_AMOUNT 8
|
||||
|
||||
//When passively preloading assets, how many to send at once? Too high creates noticable lag where as too low can flood the client's cache with "verify" files
|
||||
#define ASSET_CACHE_PRELOAD_CONCURRENT 3
|
||||
|
||||
/client
|
||||
var/list/cache = list() // List of all assets sent to this client by the asset cache.
|
||||
var/list/completed_asset_jobs = list() // List of all completed jobs, awaiting acknowledgement.
|
||||
var/list/sending = list()
|
||||
var/last_asset_job = 0 // Last job done.
|
||||
|
||||
//This proc sends the asset to the client, but only if it needs it.
|
||||
//This proc blocks(sleeps) unless verify is set to false
|
||||
/proc/send_asset(client/client, asset_name, verify = TRUE)
|
||||
if(!istype(client))
|
||||
if(ismob(client))
|
||||
var/mob/M = client
|
||||
if(M.client)
|
||||
client = M.client
|
||||
|
||||
else
|
||||
return 0
|
||||
|
||||
else
|
||||
return 0
|
||||
|
||||
if(client.cache.Find(asset_name) || client.sending.Find(asset_name))
|
||||
return 0
|
||||
|
||||
client << browse_rsc(SSassets.cache[asset_name], asset_name)
|
||||
if(!verify)
|
||||
client.cache += asset_name
|
||||
return 1
|
||||
|
||||
client.sending |= asset_name
|
||||
var/job = ++client.last_asset_job
|
||||
|
||||
client << browse({"
|
||||
<script>
|
||||
window.location.href="?asset_cache_confirm_arrival=[job]"
|
||||
</script>
|
||||
"}, "window=asset_cache_browser")
|
||||
|
||||
var/t = 0
|
||||
var/timeout_time = (ASSET_CACHE_SEND_TIMEOUT * client.sending.len) + ASSET_CACHE_SEND_TIMEOUT
|
||||
while(client && !client.completed_asset_jobs.Find(job) && t < timeout_time) // Reception is handled in Topic()
|
||||
stoplag(1) // Lock up the caller until this is received.
|
||||
t++
|
||||
|
||||
if(client)
|
||||
client.sending -= asset_name
|
||||
client.cache |= asset_name
|
||||
client.completed_asset_jobs -= job
|
||||
|
||||
return 1
|
||||
|
||||
//This proc blocks(sleeps) unless verify is set to false
|
||||
/proc/send_asset_list(client/client, list/asset_list, verify = TRUE)
|
||||
if(!istype(client))
|
||||
if(ismob(client))
|
||||
var/mob/M = client
|
||||
if(M.client)
|
||||
client = M.client
|
||||
|
||||
else
|
||||
return 0
|
||||
|
||||
else
|
||||
return 0
|
||||
|
||||
var/list/unreceived = asset_list - (client.cache + client.sending)
|
||||
if(!unreceived || !unreceived.len)
|
||||
return 0
|
||||
if (unreceived.len >= ASSET_CACHE_TELL_CLIENT_AMOUNT)
|
||||
to_chat(client, "Sending Resources...")
|
||||
for(var/asset in unreceived)
|
||||
if (asset in SSassets.cache)
|
||||
client << browse_rsc(SSassets.cache[asset], asset)
|
||||
|
||||
if(!verify) // Can't access the asset cache browser, rip.
|
||||
client.cache += unreceived
|
||||
return 1
|
||||
|
||||
client.sending |= unreceived
|
||||
var/job = ++client.last_asset_job
|
||||
|
||||
client << browse({"
|
||||
<script>
|
||||
window.location.href="?asset_cache_confirm_arrival=[job]"
|
||||
</script>
|
||||
"}, "window=asset_cache_browser")
|
||||
|
||||
var/t = 0
|
||||
var/timeout_time = ASSET_CACHE_SEND_TIMEOUT * client.sending.len
|
||||
while(client && !client.completed_asset_jobs.Find(job) && t < timeout_time) // Reception is handled in Topic()
|
||||
stoplag(1) // Lock up the caller until this is received.
|
||||
t++
|
||||
|
||||
if(client)
|
||||
client.sending -= unreceived
|
||||
client.cache |= unreceived
|
||||
client.completed_asset_jobs -= job
|
||||
|
||||
return 1
|
||||
|
||||
//This proc will download the files without clogging up the browse() queue, used for passively sending files on connection start.
|
||||
//The proc calls procs that sleep for long times.
|
||||
/proc/getFilesSlow(client/client, list/files, register_asset = TRUE)
|
||||
var/concurrent_tracker = 1
|
||||
for(var/file in files)
|
||||
if (!client)
|
||||
break
|
||||
if (register_asset)
|
||||
register_asset(file, files[file])
|
||||
if (concurrent_tracker >= ASSET_CACHE_PRELOAD_CONCURRENT)
|
||||
concurrent_tracker = 1
|
||||
send_asset(client, file)
|
||||
else
|
||||
concurrent_tracker++
|
||||
send_asset(client, file, verify=FALSE)
|
||||
|
||||
stoplag(0) //queuing calls like this too quickly can cause issues in some client versions
|
||||
|
||||
//This proc "registers" an asset, it adds it to the cache for further use, you cannot touch it from this point on or you'll fuck things up.
|
||||
//if it's an icon or something be careful, you'll have to copy it before further use.
|
||||
/proc/register_asset(asset_name, asset)
|
||||
SSassets.cache[asset_name] = asset
|
||||
|
||||
//Generated names do not include file extention.
|
||||
//Used mainly for code that deals with assets in a generic way
|
||||
//The same asset will always lead to the same asset name
|
||||
/proc/generate_asset_name(file)
|
||||
return "asset.[md5(fcopy_rsc(file))]"
|
||||
|
||||
|
||||
//These datums are used to populate the asset cache, the proc "register()" does this.
|
||||
|
||||
//all of our asset datums, used for referring to these later
|
||||
GLOBAL_LIST_EMPTY(asset_datums)
|
||||
|
||||
//get an assetdatum or make a new one
|
||||
/proc/get_asset_datum(type)
|
||||
return GLOB.asset_datums[type] || new type()
|
||||
|
||||
/datum/asset
|
||||
var/_abstract = /datum/asset
|
||||
|
||||
/datum/asset/New()
|
||||
GLOB.asset_datums[type] = src
|
||||
register()
|
||||
|
||||
/datum/asset/proc/register()
|
||||
return
|
||||
|
||||
/datum/asset/proc/send(client)
|
||||
return
|
||||
|
||||
|
||||
//If you don't need anything complicated.
|
||||
/datum/asset/simple
|
||||
_abstract = /datum/asset/simple
|
||||
var/assets = list()
|
||||
var/verify = FALSE
|
||||
|
||||
/datum/asset/simple/register()
|
||||
for(var/asset_name in assets)
|
||||
register_asset(asset_name, assets[asset_name])
|
||||
|
||||
/datum/asset/simple/send(client)
|
||||
send_asset_list(client,assets,verify)
|
||||
|
||||
|
||||
// For registering or sending multiple others at once
|
||||
/datum/asset/group
|
||||
_abstract = /datum/asset/group
|
||||
var/list/children
|
||||
|
||||
/datum/asset/group/register()
|
||||
for(var/type in children)
|
||||
get_asset_datum(type)
|
||||
|
||||
/datum/asset/group/send(client/C)
|
||||
for(var/type in children)
|
||||
var/datum/asset/A = get_asset_datum(type)
|
||||
A.send(C)
|
||||
|
||||
|
||||
// spritesheet implementation - coalesces various icons into a single .png file
|
||||
// and uses CSS to select icons out of that file - saves on transferring some
|
||||
// 1400-odd individual PNG files
|
||||
#define SPR_SIZE 1
|
||||
#define SPR_IDX 2
|
||||
#define SPRSZ_COUNT 1
|
||||
#define SPRSZ_ICON 2
|
||||
#define SPRSZ_STRIPPED 3
|
||||
|
||||
/datum/asset/spritesheet
|
||||
_abstract = /datum/asset/spritesheet
|
||||
var/name
|
||||
var/list/sizes = list() // "32x32" -> list(10, icon/normal, icon/stripped)
|
||||
var/list/sprites = list() // "foo_bar" -> list("32x32", 5)
|
||||
var/verify = FALSE
|
||||
|
||||
/datum/asset/spritesheet/register()
|
||||
if (!name)
|
||||
CRASH("spritesheet [type] cannot register without a name")
|
||||
ensure_stripped()
|
||||
|
||||
var/res_name = "spritesheet_[name].css"
|
||||
var/fname = "data/spritesheets/[res_name]"
|
||||
fdel(fname)
|
||||
text2file(generate_css(), fname)
|
||||
register_asset(res_name, fcopy_rsc(fname))
|
||||
fdel(fname)
|
||||
|
||||
for(var/size_id in sizes)
|
||||
var/size = sizes[size_id]
|
||||
register_asset("[name]_[size_id].png", size[SPRSZ_STRIPPED])
|
||||
|
||||
/datum/asset/spritesheet/send(client/C)
|
||||
if (!name)
|
||||
return
|
||||
var/all = list("spritesheet_[name].css")
|
||||
for(var/size_id in sizes)
|
||||
all += "[name]_[size_id].png"
|
||||
send_asset_list(C, all, verify)
|
||||
|
||||
/datum/asset/spritesheet/proc/ensure_stripped(sizes_to_strip = sizes)
|
||||
for(var/size_id in sizes_to_strip)
|
||||
var/size = sizes[size_id]
|
||||
if (size[SPRSZ_STRIPPED])
|
||||
continue
|
||||
|
||||
// save flattened version
|
||||
var/fname = "data/spritesheets/[name]_[size_id].png"
|
||||
fcopy(size[SPRSZ_ICON], fname)
|
||||
var/error = rustg_dmi_strip_metadata(fname)
|
||||
if(length(error))
|
||||
stack_trace("Failed to strip [name]_[size_id].png: [error]")
|
||||
size[SPRSZ_STRIPPED] = icon(fname)
|
||||
fdel(fname)
|
||||
|
||||
/datum/asset/spritesheet/proc/generate_css()
|
||||
var/list/out = list()
|
||||
|
||||
for (var/size_id in sizes)
|
||||
var/size = sizes[size_id]
|
||||
var/icon/tiny = size[SPRSZ_ICON]
|
||||
out += ".[name][size_id]{display:inline-block;width:[tiny.Width()]px;height:[tiny.Height()]px;background:url('[name]_[size_id].png') no-repeat;}"
|
||||
|
||||
for (var/sprite_id in sprites)
|
||||
var/sprite = sprites[sprite_id]
|
||||
var/size_id = sprite[SPR_SIZE]
|
||||
var/idx = sprite[SPR_IDX]
|
||||
var/size = sizes[size_id]
|
||||
|
||||
var/icon/tiny = size[SPRSZ_ICON]
|
||||
var/icon/big = size[SPRSZ_STRIPPED]
|
||||
var/per_line = big.Width() / tiny.Width()
|
||||
var/x = (idx % per_line) * tiny.Width()
|
||||
var/y = round(idx / per_line) * tiny.Height()
|
||||
|
||||
out += ".[name][size_id].[sprite_id]{background-position:-[x]px -[y]px;}"
|
||||
|
||||
return out.Join("\n")
|
||||
|
||||
/datum/asset/spritesheet/proc/Insert(sprite_name, icon/I, icon_state="", dir=SOUTH, frame=1, moving=FALSE)
|
||||
I = icon(I, icon_state=icon_state, dir=dir, frame=frame, moving=moving)
|
||||
if (!I || !length(icon_states(I))) // that direction or state doesn't exist
|
||||
return
|
||||
var/size_id = "[I.Width()]x[I.Height()]"
|
||||
var/size = sizes[size_id]
|
||||
|
||||
if (sprites[sprite_name])
|
||||
CRASH("duplicate sprite \"[sprite_name]\" in sheet [name] ([type])")
|
||||
|
||||
if (size)
|
||||
var/position = size[SPRSZ_COUNT]++
|
||||
var/icon/sheet = size[SPRSZ_ICON]
|
||||
size[SPRSZ_STRIPPED] = null
|
||||
sheet.Insert(I, icon_state=sprite_name)
|
||||
sprites[sprite_name] = list(size_id, position)
|
||||
else
|
||||
sizes[size_id] = size = list(1, I, null)
|
||||
sprites[sprite_name] = list(size_id, 0)
|
||||
|
||||
/datum/asset/spritesheet/proc/InsertAll(prefix, icon/I, list/directions)
|
||||
if (length(prefix))
|
||||
prefix = "[prefix]-"
|
||||
|
||||
if (!directions)
|
||||
directions = list(SOUTH)
|
||||
|
||||
for (var/icon_state_name in icon_states(I))
|
||||
for (var/direction in directions)
|
||||
var/prefix2 = (directions.len > 1) ? "[dir2text(direction)]-" : ""
|
||||
Insert("[prefix][prefix2][icon_state_name]", I, icon_state=icon_state_name, dir=direction)
|
||||
|
||||
/datum/asset/spritesheet/proc/css_tag()
|
||||
return {"<link rel="stylesheet" href="spritesheet_[name].css" />"}
|
||||
|
||||
/datum/asset/spritesheet/proc/icon_tag(sprite_name)
|
||||
var/sprite = sprites[sprite_name]
|
||||
if (!sprite)
|
||||
return null
|
||||
var/size_id = sprite[SPR_SIZE]
|
||||
return {"<span class="[name][size_id] [sprite_name]"></span>"}
|
||||
|
||||
/datum/asset/spritesheet/proc/icon_class_name(sprite_name)
|
||||
var/sprite = sprites[sprite_name]
|
||||
if (!sprite)
|
||||
return null
|
||||
var/size_id = sprite[SPR_SIZE]
|
||||
return {"[name][size_id] [sprite_name]"}
|
||||
|
||||
#undef SPR_SIZE
|
||||
#undef SPR_IDX
|
||||
#undef SPRSZ_COUNT
|
||||
#undef SPRSZ_ICON
|
||||
#undef SPRSZ_STRIPPED
|
||||
|
||||
|
||||
/datum/asset/spritesheet/simple
|
||||
_abstract = /datum/asset/spritesheet/simple
|
||||
var/list/assets
|
||||
|
||||
/datum/asset/spritesheet/simple/register()
|
||||
for (var/key in assets)
|
||||
Insert(key, assets[key])
|
||||
..()
|
||||
|
||||
//Generates assets based on iconstates of a single icon
|
||||
/datum/asset/simple/icon_states
|
||||
_abstract = /datum/asset/simple/icon_states
|
||||
var/icon
|
||||
var/list/directions = list(SOUTH)
|
||||
var/frame = 1
|
||||
var/movement_states = FALSE
|
||||
|
||||
var/prefix = "default" //asset_name = "[prefix].[icon_state_name].png"
|
||||
var/generic_icon_names = FALSE //generate icon filenames using generate_asset_name() instead the above format
|
||||
|
||||
verify = FALSE
|
||||
|
||||
/datum/asset/simple/icon_states/register(_icon = icon)
|
||||
for(var/icon_state_name in icon_states(_icon))
|
||||
for(var/direction in directions)
|
||||
var/asset = icon(_icon, icon_state_name, direction, frame, movement_states)
|
||||
if (!asset)
|
||||
continue
|
||||
asset = fcopy_rsc(asset) //dedupe
|
||||
var/prefix2 = (directions.len > 1) ? "[dir2text(direction)]." : ""
|
||||
var/asset_name = sanitize_filename("[prefix].[prefix2][icon_state_name].png")
|
||||
if (generic_icon_names)
|
||||
asset_name = "[generate_asset_name(asset)].png"
|
||||
|
||||
register_asset(asset_name, asset)
|
||||
|
||||
/datum/asset/simple/icon_states/multiple_icons
|
||||
_abstract = /datum/asset/simple/icon_states/multiple_icons
|
||||
var/list/icons
|
||||
|
||||
/datum/asset/simple/icon_states/multiple_icons/register()
|
||||
for(var/i in icons)
|
||||
..(i)
|
||||
|
||||
|
||||
//DEFINITIONS FOR ASSET DATUMS START HERE.
|
||||
|
||||
/* uncomment this and delete the tgui def bellow this for the new tgui
|
||||
/datum/asset/simple/tgui
|
||||
assets = list(
|
||||
// tgui
|
||||
"tgui.bundle.js" = 'tgui/packages/tgui/public/tgui.bundle.js',
|
||||
"tgui.bundle.css" = 'tgui/packages/tgui/public/tgui.bundle.css',
|
||||
)
|
||||
*/
|
||||
/datum/asset/simple/tgui
|
||||
assets = list(
|
||||
// Old TGUI
|
||||
"tgui.css" = 'tgui/assets/tgui.css',
|
||||
"tgui.js" = 'tgui/assets/tgui.js',
|
||||
// tgui-next
|
||||
"tgui-main.html" = 'tgui-next/packages/tgui/public/tgui-main.html',
|
||||
"tgui-fallback.html" = 'tgui-next/packages/tgui/public/tgui-fallback.html',
|
||||
"tgui.bundle.js" = 'tgui-next/packages/tgui/public/tgui.bundle.js',
|
||||
"tgui.bundle.css" = 'tgui-next/packages/tgui/public/tgui.bundle.css',
|
||||
// Old TGUI compatability
|
||||
"tgui-fallback.html" = 'tgui-next/packages/tgui/public/tgui-fallback.html',
|
||||
"shim-html5shiv.js" = 'tgui-next/packages/tgui/public/shim-html5shiv.js',
|
||||
"shim-ie8.js" = 'tgui-next/packages/tgui/public/shim-ie8.js',
|
||||
"shim-dom4.js" = 'tgui-next/packages/tgui/public/shim-dom4.js',
|
||||
@@ -434,8 +57,16 @@ GLOBAL_LIST_EMPTY(asset_datums)
|
||||
"smmon_4.gif" = 'icons/program_icons/smmon_4.gif',
|
||||
"smmon_5.gif" = 'icons/program_icons/smmon_5.gif',
|
||||
"smmon_6.gif" = 'icons/program_icons/smmon_6.gif'
|
||||
//"borg_mon.gif" = 'icons/program_icons/borg_mon.gif'
|
||||
)
|
||||
|
||||
/* uncomment if you're porting the new ntnet app
|
||||
/datum/asset/simple/radar_assets
|
||||
assets = list(
|
||||
"ntosradarbackground.png" = 'icons/UI_Icons/tgui/ntosradar_background.png',
|
||||
"ntosradarpointer.png" = 'icons/UI_Icons/tgui/ntosradar_pointer.png',
|
||||
"ntosradarpointerS.png" = 'icons/UI_Icons/tgui/ntosradar_pointer_S.png'
|
||||
)
|
||||
*/
|
||||
/datum/asset/spritesheet/simple/pda
|
||||
name = "pda"
|
||||
assets = list(
|
||||
@@ -464,6 +95,7 @@ GLOBAL_LIST_EMPTY(asset_datums)
|
||||
"refresh" = 'icons/pda_icons/pda_refresh.png',
|
||||
"scanner" = 'icons/pda_icons/pda_scanner.png',
|
||||
"signaler" = 'icons/pda_icons/pda_signaler.png',
|
||||
//"skills" = 'icons/pda_icons/pda_skills.png',
|
||||
"status" = 'icons/pda_icons/pda_status.png',
|
||||
"dronephone" = 'icons/pda_icons/pda_dronephone.png',
|
||||
"emoji" = 'icons/pda_icons/pda_emoji.png'
|
||||
@@ -483,51 +115,10 @@ GLOBAL_LIST_EMPTY(asset_datums)
|
||||
"stamp-cap" = 'icons/stamp_icons/large_stamp-cap.png',
|
||||
"stamp-qm" = 'icons/stamp_icons/large_stamp-qm.png',
|
||||
"stamp-law" = 'icons/stamp_icons/large_stamp-law.png'
|
||||
)
|
||||
|
||||
/datum/asset/spritesheet/simple/minesweeper
|
||||
name = "minesweeper"
|
||||
assets = list(
|
||||
"1" = 'icons/UI_Icons/minesweeper_tiles/one.png',
|
||||
"2" = 'icons/UI_Icons/minesweeper_tiles/two.png',
|
||||
"3" = 'icons/UI_Icons/minesweeper_tiles/three.png',
|
||||
"4" = 'icons/UI_Icons/minesweeper_tiles/four.png',
|
||||
"5" = 'icons/UI_Icons/minesweeper_tiles/five.png',
|
||||
"6" = 'icons/UI_Icons/minesweeper_tiles/six.png',
|
||||
"7" = 'icons/UI_Icons/minesweeper_tiles/seven.png',
|
||||
"8" = 'icons/UI_Icons/minesweeper_tiles/eight.png',
|
||||
"empty" = 'icons/UI_Icons/minesweeper_tiles/empty.png',
|
||||
"flag" = 'icons/UI_Icons/minesweeper_tiles/flag.png',
|
||||
"hidden" = 'icons/UI_Icons/minesweeper_tiles/hidden.png',
|
||||
"mine" = 'icons/UI_Icons/minesweeper_tiles/mine.png',
|
||||
"minehit" = 'icons/UI_Icons/minesweeper_tiles/minehit.png'
|
||||
)
|
||||
|
||||
/datum/asset/spritesheet/simple/pills
|
||||
name = "pills"
|
||||
assets = list(
|
||||
"pill1" = 'icons/UI_Icons/Pills/pill1.png',
|
||||
"pill2" = 'icons/UI_Icons/Pills/pill2.png',
|
||||
"pill3" = 'icons/UI_Icons/Pills/pill3.png',
|
||||
"pill4" = 'icons/UI_Icons/Pills/pill4.png',
|
||||
"pill5" = 'icons/UI_Icons/Pills/pill5.png',
|
||||
"pill6" = 'icons/UI_Icons/Pills/pill6.png',
|
||||
"pill7" = 'icons/UI_Icons/Pills/pill7.png',
|
||||
"pill8" = 'icons/UI_Icons/Pills/pill8.png',
|
||||
"pill9" = 'icons/UI_Icons/Pills/pill9.png',
|
||||
"pill10" = 'icons/UI_Icons/Pills/pill10.png',
|
||||
"pill11" = 'icons/UI_Icons/Pills/pill11.png',
|
||||
"pill12" = 'icons/UI_Icons/Pills/pill12.png',
|
||||
"pill13" = 'icons/UI_Icons/Pills/pill13.png',
|
||||
"pill14" = 'icons/UI_Icons/Pills/pill14.png',
|
||||
"pill15" = 'icons/UI_Icons/Pills/pill15.png',
|
||||
"pill16" = 'icons/UI_Icons/Pills/pill16.png',
|
||||
"pill17" = 'icons/UI_Icons/Pills/pill17.png',
|
||||
"pill18" = 'icons/UI_Icons/Pills/pill18.png',
|
||||
"pill19" = 'icons/UI_Icons/Pills/pill19.png',
|
||||
"pill20" = 'icons/UI_Icons/Pills/pill20.png',
|
||||
"pill21" = 'icons/UI_Icons/Pills/pill21.png',
|
||||
"pill22" = 'icons/UI_Icons/Pills/pill22.png',
|
||||
//"stamp-chap" = 'icons/stamp_icons/large_stamp-chap.png',
|
||||
//"stamp-mime" = 'icons/stamp_icons/large_stamp-mime.png',
|
||||
//"stamp-centcom" = 'icons/stamp_icons/large_stamp-centcom.png',
|
||||
//"stamp-syndicate" = 'icons/stamp_icons/large_stamp-syndicate.png'
|
||||
)
|
||||
|
||||
/datum/asset/simple/IRV
|
||||
@@ -573,23 +164,20 @@ GLOBAL_LIST_EMPTY(asset_datums)
|
||||
)
|
||||
|
||||
/datum/asset/simple/jquery
|
||||
verify = FALSE
|
||||
assets = list(
|
||||
"jquery.min.js" = 'code/modules/goonchat/browserassets/js/jquery.min.js',
|
||||
)
|
||||
|
||||
/datum/asset/simple/goonchat
|
||||
verify = FALSE
|
||||
assets = list(
|
||||
"json2.min.js" = 'code/modules/goonchat/browserassets/js/json2.min.js',
|
||||
"browserOutput.js" = 'code/modules/goonchat/browserassets/js/browserOutput.js',
|
||||
"browserOutput.css" = 'code/modules/goonchat/browserassets/css/browserOutput.css',
|
||||
"browserOutput_dark.css" = 'code/modules/goonchat/browserassets/css/browserOutput_dark.css',
|
||||
"browserOutput_dark.css" = 'code/modules/goonchat/browserassets/css/browserOutput_dark.css', //dark theme, cit specific
|
||||
"browserOutput_light.css" = 'code/modules/goonchat/browserassets/css/browserOutput_light.css'
|
||||
)
|
||||
|
||||
/datum/asset/simple/fontawesome
|
||||
verify = FALSE
|
||||
assets = list(
|
||||
"fa-regular-400.eot" = 'html/font-awesome/webfonts/fa-regular-400.eot',
|
||||
"fa-regular-400.woff" = 'html/font-awesome/webfonts/fa-regular-400.woff',
|
||||
@@ -630,6 +218,90 @@ GLOBAL_LIST_EMPTY(asset_datums)
|
||||
"none_button.png" = 'html/none_button.png',
|
||||
)
|
||||
|
||||
/datum/asset/spritesheet/simple/minesweeper
|
||||
name = "minesweeper"
|
||||
assets = list(
|
||||
"1" = 'icons/UI_Icons/minesweeper_tiles/one.png',
|
||||
"2" = 'icons/UI_Icons/minesweeper_tiles/two.png',
|
||||
"3" = 'icons/UI_Icons/minesweeper_tiles/three.png',
|
||||
"4" = 'icons/UI_Icons/minesweeper_tiles/four.png',
|
||||
"5" = 'icons/UI_Icons/minesweeper_tiles/five.png',
|
||||
"6" = 'icons/UI_Icons/minesweeper_tiles/six.png',
|
||||
"7" = 'icons/UI_Icons/minesweeper_tiles/seven.png',
|
||||
"8" = 'icons/UI_Icons/minesweeper_tiles/eight.png',
|
||||
"empty" = 'icons/UI_Icons/minesweeper_tiles/empty.png',
|
||||
"flag" = 'icons/UI_Icons/minesweeper_tiles/flag.png',
|
||||
"hidden" = 'icons/UI_Icons/minesweeper_tiles/hidden.png',
|
||||
"mine" = 'icons/UI_Icons/minesweeper_tiles/mine.png',
|
||||
"minehit" = 'icons/UI_Icons/minesweeper_tiles/minehit.png'
|
||||
)
|
||||
|
||||
/* Port the app game thing
|
||||
/datum/asset/simple/arcade
|
||||
assets = list(
|
||||
"boss1.gif" = 'icons/UI_Icons/Arcade/boss1.gif',
|
||||
"boss2.gif" = 'icons/UI_Icons/Arcade/boss2.gif',
|
||||
"boss3.gif" = 'icons/UI_Icons/Arcade/boss3.gif',
|
||||
"boss4.gif" = 'icons/UI_Icons/Arcade/boss4.gif',
|
||||
"boss5.gif" = 'icons/UI_Icons/Arcade/boss5.gif',
|
||||
"boss6.gif" = 'icons/UI_Icons/Arcade/boss6.gif',
|
||||
)
|
||||
*/
|
||||
/*
|
||||
/datum/asset/spritesheet/simple/achievements
|
||||
name ="achievements"
|
||||
assets = list(
|
||||
"default" = 'icons/UI_Icons/Achievements/default.png',
|
||||
"basemisc" = 'icons/UI_Icons/Achievements/basemisc.png',
|
||||
"baseboss" = 'icons/UI_Icons/Achievements/baseboss.png',
|
||||
"baseskill" = 'icons/UI_Icons/Achievements/baseskill.png',
|
||||
"bbgum" = 'icons/UI_Icons/Achievements/Boss/bbgum.png',
|
||||
"colossus" = 'icons/UI_Icons/Achievements/Boss/colossus.png',
|
||||
"hierophant" = 'icons/UI_Icons/Achievements/Boss/hierophant.png',
|
||||
"legion" = 'icons/UI_Icons/Achievements/Boss/legion.png',
|
||||
"miner" = 'icons/UI_Icons/Achievements/Boss/miner.png',
|
||||
"swarmer" = 'icons/UI_Icons/Achievements/Boss/swarmer.png',
|
||||
"tendril" = 'icons/UI_Icons/Achievements/Boss/tendril.png',
|
||||
"featofstrength" = 'icons/UI_Icons/Achievements/Misc/featofstrength.png',
|
||||
"helbital" = 'icons/UI_Icons/Achievements/Misc/helbital.png',
|
||||
"jackpot" = 'icons/UI_Icons/Achievements/Misc/jackpot.png',
|
||||
"meteors" = 'icons/UI_Icons/Achievements/Misc/meteors.png',
|
||||
"timewaste" = 'icons/UI_Icons/Achievements/Misc/timewaste.png',
|
||||
"upgrade" = 'icons/UI_Icons/Achievements/Misc/upgrade.png',
|
||||
"clownking" = 'icons/UI_Icons/Achievements/Misc/clownking.png',
|
||||
"clownthanks" = 'icons/UI_Icons/Achievements/Misc/clownthanks.png',
|
||||
"rule8" = 'icons/UI_Icons/Achievements/Misc/rule8.png',
|
||||
"snail" = 'icons/UI_Icons/Achievements/Misc/snail.png',
|
||||
"mining" = 'icons/UI_Icons/Achievements/Skills/mining.png',
|
||||
)
|
||||
*/
|
||||
/datum/asset/spritesheet/simple/pills
|
||||
name ="pills"
|
||||
assets = list(
|
||||
"pill1" = 'icons/UI_Icons/Pills/pill1.png',
|
||||
"pill2" = 'icons/UI_Icons/Pills/pill2.png',
|
||||
"pill3" = 'icons/UI_Icons/Pills/pill3.png',
|
||||
"pill4" = 'icons/UI_Icons/Pills/pill4.png',
|
||||
"pill5" = 'icons/UI_Icons/Pills/pill5.png',
|
||||
"pill6" = 'icons/UI_Icons/Pills/pill6.png',
|
||||
"pill7" = 'icons/UI_Icons/Pills/pill7.png',
|
||||
"pill8" = 'icons/UI_Icons/Pills/pill8.png',
|
||||
"pill9" = 'icons/UI_Icons/Pills/pill9.png',
|
||||
"pill10" = 'icons/UI_Icons/Pills/pill10.png',
|
||||
"pill11" = 'icons/UI_Icons/Pills/pill11.png',
|
||||
"pill12" = 'icons/UI_Icons/Pills/pill12.png',
|
||||
"pill13" = 'icons/UI_Icons/Pills/pill13.png',
|
||||
"pill14" = 'icons/UI_Icons/Pills/pill14.png',
|
||||
"pill15" = 'icons/UI_Icons/Pills/pill15.png',
|
||||
"pill16" = 'icons/UI_Icons/Pills/pill16.png',
|
||||
"pill17" = 'icons/UI_Icons/Pills/pill17.png',
|
||||
"pill18" = 'icons/UI_Icons/Pills/pill18.png',
|
||||
"pill19" = 'icons/UI_Icons/Pills/pill19.png',
|
||||
"pill20" = 'icons/UI_Icons/Pills/pill20.png',
|
||||
"pill21" = 'icons/UI_Icons/Pills/pill21.png',
|
||||
"pill22" = 'icons/UI_Icons/Pills/pill22.png',
|
||||
)
|
||||
|
||||
//this exists purely to avoid meta by pre-loading all language icons.
|
||||
/datum/asset/language/register()
|
||||
for(var/path in typesof(/datum/language))
|
||||
@@ -640,7 +312,7 @@ GLOBAL_LIST_EMPTY(asset_datums)
|
||||
/datum/asset/spritesheet/pipes
|
||||
name = "pipes"
|
||||
|
||||
/datum/asset/spritesheet/pipes/register()
|
||||
/datum/asset/spritesheet/pipes/register() //we do not have chempipes
|
||||
for (var/each in list('icons/obj/atmospherics/pipes/pipe_item.dmi', 'icons/obj/atmospherics/pipes/disposal.dmi', 'icons/obj/atmospherics/pipes/transit_tube.dmi'))
|
||||
InsertAll("", each, GLOB.alldirs)
|
||||
..()
|
||||
@@ -650,7 +322,7 @@ GLOBAL_LIST_EMPTY(asset_datums)
|
||||
name = "design"
|
||||
|
||||
/datum/asset/spritesheet/research_designs/register()
|
||||
for (var/path in subtypesof(/datum/design))
|
||||
for(var/path in subtypesof(/datum/design))
|
||||
var/datum/design/D = path
|
||||
|
||||
var/icon_file
|
||||
@@ -0,0 +1,28 @@
|
||||
<!DOCTYPE html>
|
||||
<html lang="en">
|
||||
<head>
|
||||
<meta http-equiv="X-UA-Compatible" content="IE=edge" />
|
||||
</head>
|
||||
<body>
|
||||
<script>
|
||||
//this is used over window.location because window.location has a character limit in IE.
|
||||
function sendbyond(text) {
|
||||
var xhr = new XMLHttpRequest();
|
||||
xhr.open('GET', '?'+text, true);
|
||||
xhr.send(null);
|
||||
}
|
||||
var xhr = new XMLHttpRequest();
|
||||
xhr.open('GET', 'asset_data.json', true);
|
||||
xhr.responseType = 'text';
|
||||
xhr.onreadystatechange = function () {
|
||||
if (xhr.readyState === 4) {
|
||||
var status = xhr.status;
|
||||
if (status >= 200 && status < 400) {
|
||||
sendbyond('asset_cache_preload_data=' + encodeURIComponent(xhr.responseText));
|
||||
}
|
||||
}
|
||||
};
|
||||
xhr.send(null);
|
||||
</script>
|
||||
</body>
|
||||
</html>
|
||||
@@ -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
|
||||
|
||||
@@ -430,3 +430,40 @@
|
||||
crate_type = /obj/structure/closet/crate
|
||||
|
||||
|
||||
///Special supply crate that generates random syndicate gear up to a determined TC value
|
||||
|
||||
/datum/supply_pack/misc/syndicate
|
||||
|
||||
name = "Assorted Syndicate Gear"
|
||||
|
||||
desc = "Contains a random assortment of syndicate gear."
|
||||
|
||||
special = TRUE ///Cannot be ordered via cargo
|
||||
|
||||
contains = list()
|
||||
|
||||
crate_name = "syndicate gear crate"
|
||||
|
||||
crate_type = /obj/structure/closet/crate
|
||||
|
||||
var/crate_value = 30 ///Total TC worth of contained uplink items
|
||||
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////////
|
||||
//////////////////////////////// Syndicate Packs /////////////////////////////
|
||||
//////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
//Generate assorted uplink items, taking into account the same surplus modifiers used for surplus crates
|
||||
//(this is exclusively used for the rare variant of the stray cargo event!)
|
||||
/datum/supply_pack/misc/syndicate/fill(obj/structure/closet/crate/C)
|
||||
var/list/uplink_items = get_uplink_items(SSticker.mode)
|
||||
while(crate_value)
|
||||
var/category = pick(uplink_items)
|
||||
var/item = pick(uplink_items[category])
|
||||
var/datum/uplink_item/I = uplink_items[category][item]
|
||||
if(!I.surplus || prob(100 - I.surplus))
|
||||
continue
|
||||
if(crate_value < I.cost)
|
||||
continue
|
||||
crate_value -= I.cost
|
||||
new I.item(C)
|
||||
@@ -228,3 +228,35 @@
|
||||
access = ACCESS_ARMORY
|
||||
crate_name = "sporting crate"
|
||||
crate_type = /obj/structure/closet/crate/secure // Would have liked a wooden crate but access >:(
|
||||
|
||||
/datum/supply_pack/security/dumdum
|
||||
name = ".38 DumDum Speedloader"
|
||||
desc = "Contains one speedloader of .38 DumDum ammunition, good for embedding in soft targets. Requires Security or Forensics access to open."
|
||||
cost = 1200
|
||||
access = FALSE
|
||||
access_any = list(ACCESS_SECURITY, ACCESS_FORENSICS_LOCKERS)
|
||||
contains = list(/obj/item/ammo_box/c38/dumdum)
|
||||
crate_name = ".38 match crate"
|
||||
|
||||
/datum/supply_pack/security/match
|
||||
name = ".38 Match Grade Speedloader"
|
||||
desc = "Contains one speedloader of match grade .38 ammunition, perfect for showing off trickshots. Requires Security or Forensics access to open."
|
||||
cost = 1200
|
||||
access = FALSE
|
||||
access_any = list(ACCESS_SECURITY, ACCESS_FORENSICS_LOCKERS)
|
||||
contains = list(/obj/item/ammo_box/c38/match)
|
||||
crate_name = ".38 match crate"
|
||||
|
||||
/datum/supply_pack/security/stingpack
|
||||
name = "Stingbang Grenade Pack"
|
||||
desc = "Contains five \"stingbang\" grenades, perfect for stopping riots and playing morally unthinkable pranks. Requires Security access to open."
|
||||
cost = 2500
|
||||
contains = list(/obj/item/storage/box/stingbangs)
|
||||
crate_name = "stingbang grenade pack crate"
|
||||
|
||||
/datum/supply_pack/security/stingpack/single
|
||||
name = "Stingbang Single-Pack"
|
||||
desc = "Contains one \"stingbang\" grenade, perfect for playing meanhearted pranks. Requires Security access to open."
|
||||
cost = 1400
|
||||
contains = list(/obj/item/grenade/stingbang)
|
||||
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -36,29 +36,11 @@ GLOBAL_LIST_INIT(blacklisted_builds, list(
|
||||
if(!usr || usr != mob) //stops us calling Topic for somebody else's client. Also helps prevent usr=null
|
||||
return
|
||||
|
||||
// asset_cache
|
||||
var/asset_cache_job
|
||||
if(href_list["asset_cache_confirm_arrival"])
|
||||
var/job = text2num(href_list["asset_cache_confirm_arrival"])
|
||||
//because we skip the limiter, we have to make sure this is a valid arrival and not somebody tricking us
|
||||
// into letting append to a list without limit.
|
||||
if (job && job <= last_asset_job && !(job in completed_asset_jobs))
|
||||
completed_asset_jobs += job
|
||||
asset_cache_job = asset_cache_confirm_arrival(href_list["asset_cache_confirm_arrival"])
|
||||
if (!asset_cache_job)
|
||||
return
|
||||
else if (job in completed_asset_jobs) //byond bug ID:2256651
|
||||
to_chat(src, "<span class='danger'>An error has been detected in how your client is receiving resources. Attempting to correct.... (If you keep seeing these messages you might want to close byond and reconnect)</span>")
|
||||
src << browse("...", "window=asset_cache_browser")
|
||||
// Keypress passthrough
|
||||
if(href_list["__keydown"])
|
||||
var/keycode = browser_keycode_to_byond(href_list["__keydown"])
|
||||
if(keycode)
|
||||
keyDown(keycode)
|
||||
return
|
||||
if(href_list["__keyup"])
|
||||
var/keycode = browser_keycode_to_byond(href_list["__keyup"])
|
||||
if(keycode)
|
||||
keyUp(keycode)
|
||||
return
|
||||
|
||||
|
||||
var/mtl = CONFIG_GET(number/minute_topic_limit)
|
||||
if (!holder && mtl)
|
||||
@@ -75,7 +57,7 @@ GLOBAL_LIST_INIT(blacklisted_builds, list(
|
||||
topiclimiter[ADMINSWARNED_AT] = minute
|
||||
msg += " Administrators have been informed."
|
||||
log_game("[key_name(src)] Has hit the per-minute topic limit of [mtl] topic calls in a given game minute")
|
||||
message_admins("[ADMIN_LOOKUPFLW(src)] [ADMIN_KICK(usr)] Has hit the per-minute topic limit of [mtl] topic calls in a given game minute")
|
||||
message_admins("[ADMIN_LOOKUPFLW(usr)] [ADMIN_KICK(usr)] Has hit the per-minute topic limit of [mtl] topic calls in a given game minute")
|
||||
to_chat(src, "<span class='danger'>[msg]</span>")
|
||||
return
|
||||
|
||||
@@ -96,6 +78,27 @@ GLOBAL_LIST_INIT(blacklisted_builds, list(
|
||||
if(!(href_list["_src_"] == "chat" && href_list["proc"] == "ping" && LAZYLEN(href_list) == 2))
|
||||
log_href("[src] (usr:[usr]\[[COORD(usr)]\]) : [hsrc ? "[hsrc] " : ""][href]")
|
||||
|
||||
//byond bug ID:2256651
|
||||
if (asset_cache_job && (asset_cache_job in completed_asset_jobs))
|
||||
to_chat(src, "<span class='danger'>An error has been detected in how your client is receiving resources. Attempting to correct.... (If you keep seeing these messages you might want to close byond and reconnect)</span>")
|
||||
src << browse("...", "window=asset_cache_browser")
|
||||
return
|
||||
if (href_list["asset_cache_preload_data"])
|
||||
asset_cache_preload_data(href_list["asset_cache_preload_data"])
|
||||
return
|
||||
|
||||
// Keypress passthrough
|
||||
if(href_list["__keydown"])
|
||||
var/keycode = browser_keycode_to_byond(href_list["__keydown"])
|
||||
if(keycode)
|
||||
keyDown(keycode)
|
||||
return
|
||||
if(href_list["__keyup"])
|
||||
var/keycode = browser_keycode_to_byond(href_list["__keyup"])
|
||||
if(keycode)
|
||||
keyUp(keycode)
|
||||
return
|
||||
|
||||
// Admin PM
|
||||
if(href_list["priv_msg"])
|
||||
cmd_admin_pm(href_list["priv_msg"],null)
|
||||
@@ -858,8 +861,14 @@ GLOBAL_LIST_EMPTY(external_rsc_urls)
|
||||
'html/browser/playeroptions.css',
|
||||
)
|
||||
spawn (10) //removing this spawn causes all clients to not get verbs.
|
||||
|
||||
//load info on what assets the client has
|
||||
src << browse('code/modules/asset_cache/validate_assets.html', "window=asset_cache_browser")
|
||||
|
||||
//Precache the client with all other assets slowly, so as to not block other browse() calls
|
||||
getFilesSlow(src, SSassets.preload, register_asset = FALSE)
|
||||
addtimer(CALLBACK(GLOBAL_PROC, /proc/getFilesSlow, src, SSassets.preload, FALSE), 5 SECONDS)
|
||||
|
||||
#if (PRELOAD_RSC == 0)
|
||||
for (var/name in GLOB.vox_sounds)
|
||||
var/file = GLOB.vox_sounds[name]
|
||||
|
||||
@@ -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
|
||||
@@ -1098,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
|
||||
@@ -1110,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>"
|
||||
@@ -1133,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>"
|
||||
@@ -1158,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>
|
||||
@@ -1170,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;
|
||||
}
|
||||
@@ -1622,19 +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", features["silicon_flavor_text"], MAX_FLAVOR_LEN, TRUE)
|
||||
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"] = html_decode(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
|
||||
@@ -2372,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")
|
||||
@@ -2383,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)
|
||||
@@ -2415,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")
|
||||
@@ -2433,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")
|
||||
|
||||
@@ -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)
|
||||
@@ -552,8 +565,8 @@ 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"]
|
||||
|
||||
@@ -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,5 +6,7 @@
|
||||
if(!CONFIG_GET(flag/minimaps_enabled))
|
||||
to_chat(usr, "<span class='boldwarning'>Minimap generation is not enabled in the server's configuration.</span>")
|
||||
return
|
||||
|
||||
if(!SSminimaps.station_minimap)
|
||||
to_chat(usr, "<span class='boldwarning'>Minimap generation is in progress, please wait!</span>")
|
||||
return
|
||||
SSminimaps.station_minimap.show(src)
|
||||
|
||||
@@ -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()
|
||||
. = ..()
|
||||
|
||||
@@ -203,6 +203,12 @@
|
||||
icon_state = "hipster_glasses"
|
||||
item_state = "hipster_glasses"
|
||||
|
||||
/obj/item/clothing/glasses/regular/circle
|
||||
name = "circle glasses"
|
||||
desc = "Why would you wear something so controversial yet so brave?"
|
||||
icon_state = "circle_glasses"
|
||||
item_state = "circle_glasses"
|
||||
|
||||
//Here lies green glasses, so ugly they died. RIP
|
||||
|
||||
/obj/item/clothing/glasses/sunglasses
|
||||
|
||||
@@ -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"
|
||||
@@ -75,6 +74,10 @@
|
||||
icon_state = "beaniedurathread"
|
||||
armor = list("melee" = 25, "bullet" = 10, "laser" = 20,"energy" = 10, "bomb" = 30, "bio" = 15, "rad" = 20, "fire" = 100, "acid" = 50)
|
||||
|
||||
|
||||
/obj/item/clothing/head/beanie/waldo
|
||||
name = "red striped bobble hat"
|
||||
desc = "If you're going on a worldwide hike, you'll need some cold protection."
|
||||
icon_state = "waldo_hat"
|
||||
item_state = "waldo_hat"
|
||||
|
||||
//No dog fashion sprites yet :( poor Ian can't be dope like the rest of us yet
|
||||
@@ -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"
|
||||
@@ -386,3 +386,9 @@
|
||||
cold_protection = HEAD
|
||||
min_cold_protection_temperature = SPACE_SUIT_MIN_TEMP_PROTECT
|
||||
armor = list("melee" = 10, "bullet" = 5, "laser" = 5,"energy" = 5, "bomb" = 5, "bio" = 50, "rad" = 20, "fire" = -10, "acid" = 0)
|
||||
|
||||
/obj/item/clothing/head/helmet/police
|
||||
name = "police officer's hat"
|
||||
desc = "A police officer's Hat. This hat emphasizes that you are THE LAW."
|
||||
icon_state = "policehelm"
|
||||
dynamic_hair_suffix = ""
|
||||
|
||||
@@ -429,3 +429,11 @@
|
||||
icon_state = "russobluecamohat"
|
||||
item_state = "russobluecamohat"
|
||||
dynamic_hair_suffix = ""
|
||||
|
||||
/obj/item/clothing/head/hunter
|
||||
name = "bounty hunting hat"
|
||||
desc = "Ain't nobody gonna cheat the hangman in my town."
|
||||
icon_state = "hunter"
|
||||
item_state = "hunter"
|
||||
armor = list("melee" = 5, "bullet" = 5, "laser" = 5, "energy" = 15, "bomb" = 0, "bio" = 0, "rad" = 0, "fire" = 0, "acid" = 0)
|
||||
resistance_flags = FIRE_PROOF | ACID_PROOF
|
||||
|
||||
@@ -231,3 +231,16 @@
|
||||
A.UpdateButtonIcon()
|
||||
to_chat(M, "The Tiki Mask has now changed into the [choice] Mask!")
|
||||
return TRUE
|
||||
|
||||
/obj/item/clothing/mask/gas/tiki_mask/yalp_elor
|
||||
icon_state = "tiki_yalp"
|
||||
item_state = "tiki_yalp"
|
||||
actions_types = list()
|
||||
|
||||
/obj/item/clothing/mask/gas/hunter
|
||||
name = "bounty hunting mask"
|
||||
desc = "A custom tactical mask with decals added."
|
||||
icon_state = "hunter"
|
||||
item_state = "hunter"
|
||||
resistance_flags = FIRE_PROOF | ACID_PROOF
|
||||
flags_inv = HIDEFACIALHAIR|HIDEFACE|HIDEEYES|HIDEEARS|HIDEHAIR
|
||||
|
||||
@@ -185,3 +185,9 @@
|
||||
playsound(src.loc, "sound/voice/complionator/[phrase_sound].ogg", 100, 0, 4)
|
||||
cooldown = world.time
|
||||
cooldown_special = world.time
|
||||
|
||||
/obj/item/clothing/mask/gas/sechailer/swat/spacepol
|
||||
name = "spacepol mask"
|
||||
desc = "A close-fitting tactical mask created in cooperation with a certain megacorporation, comes with an especially aggressive Compli-o-nator 3000."
|
||||
icon_state = "spacepol"
|
||||
item_state = "spacepol"
|
||||
|
||||
@@ -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
|
||||
@@ -518,3 +518,14 @@ Contains:
|
||||
desc = "A deep blue space helmet with a large red cross on the faceplate to designate the wearer as trained emergency medical personnel."
|
||||
icon_state = "paramedic-eva-helmet"
|
||||
item_state = "paramedic-eva-helmet"
|
||||
|
||||
/obj/item/clothing/suit/space/hunter
|
||||
name = "bounty hunting suit"
|
||||
desc = "A custom version of the MK.II SWAT suit, modified to look rugged and tough. Works as a space suit, if you can find a helmet."
|
||||
icon_state = "hunter"
|
||||
item_state = "swat_suit"
|
||||
allowed = list(/obj/item/gun, /obj/item/ammo_box, /obj/item/ammo_casing, /obj/item/melee/baton, /obj/item/restraints/handcuffs, /obj/item/tank/internals, /obj/item/kitchen/knife/combat)
|
||||
armor = list("melee" = 60, "bullet" = 40, "laser" = 40, "energy" = 50, "bomb" = 100, "bio" = 100, "rad" = 100, "fire" = 100, "acid" = 100)
|
||||
strip_delay = 130
|
||||
resistance_flags = FIRE_PROOF | ACID_PROOF
|
||||
|
||||
|
||||
@@ -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"
|
||||
|
||||
@@ -1016,3 +1016,9 @@
|
||||
/obj/item/clothing/head/hooded/winterhood/polychromic
|
||||
icon_state = "winterhood_poly"
|
||||
item_state = "winterhood_poly"
|
||||
|
||||
/obj/item/clothing/suit/striped_sweater
|
||||
name = "striped sweater"
|
||||
desc = "Reminds you of someone, but you just can't put your finger on it..."
|
||||
icon_state = "waldo_shirt"
|
||||
item_state = "waldo_shirt"
|
||||
|
||||
@@ -192,3 +192,14 @@
|
||||
icon_state = "hos_parade_fem"
|
||||
item_state = "r_suit"
|
||||
fitted = FEMALE_UNIFORM_TOP
|
||||
|
||||
/*
|
||||
*Spacepol
|
||||
*/
|
||||
|
||||
/obj/item/clothing/under/rank/security/spacepol
|
||||
name = "police uniform"
|
||||
desc = "Space not controlled by megacorporations, planets, or pirates is under the jurisdiction of Spacepol."
|
||||
icon_state = "spacepol"
|
||||
item_state = "spacepol"
|
||||
can_adjust = FALSE
|
||||
@@ -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"
|
||||
|
||||
@@ -0,0 +1,33 @@
|
||||
/datum/round_event_control/brain_trauma
|
||||
name = "Spontaneous Brain Trauma"
|
||||
typepath = /datum/round_event/brain_trauma
|
||||
weight = 25
|
||||
|
||||
/datum/round_event/brain_trauma
|
||||
fakeable = FALSE
|
||||
|
||||
/datum/round_event/brain_trauma/start()
|
||||
for(var/mob/living/carbon/human/H in shuffle(GLOB.alive_mob_list))
|
||||
if(!H.client)
|
||||
continue
|
||||
if(H.stat == DEAD) // What are you doing in this list
|
||||
continue
|
||||
if(!H.getorgan(/obj/item/organ/brain)) // If only I had a brain
|
||||
continue
|
||||
|
||||
traumatize(H)
|
||||
break
|
||||
|
||||
/datum/round_event/brain_trauma/proc/traumatize(mob/living/carbon/human/H)
|
||||
var/resistance = pick(
|
||||
65;TRAUMA_RESILIENCE_BASIC,
|
||||
30;TRAUMA_RESILIENCE_SURGERY,
|
||||
5;TRAUMA_RESILIENCE_LOBOTOMY)
|
||||
|
||||
var/trauma_type = pickweight(list(
|
||||
BRAIN_TRAUMA_MILD = 60,
|
||||
BRAIN_TRAUMA_SEVERE = 30,
|
||||
BRAIN_TRAUMA_SPECIAL = 10
|
||||
))
|
||||
|
||||
H.gain_trauma_type(trauma_type, resistance)
|
||||
@@ -0,0 +1,30 @@
|
||||
/datum/round_event_control/fake_virus
|
||||
name = "Fake Virus"
|
||||
typepath = /datum/round_event/fake_virus
|
||||
weight = 20
|
||||
|
||||
/datum/round_event/fake_virus/start()
|
||||
var/list/fake_virus_victims = list()
|
||||
for(var/mob/living/carbon/human/H in shuffle(GLOB.player_list))
|
||||
if(!H.client || H.stat == DEAD || H.InCritical())
|
||||
continue
|
||||
fake_virus_victims += H
|
||||
|
||||
//first we do hard status effect victims
|
||||
var/defacto_min = min(3, LAZYLEN(fake_virus_victims))
|
||||
if(defacto_min)// event will hit 1-3 people by default, but will do 1-2 or just 1 if only those many candidates are available
|
||||
for(var/i=1; i<=rand(1,defacto_min); i++)
|
||||
var/mob/living/carbon/human/hypochondriac = pick(fake_virus_victims)
|
||||
hypochondriac.apply_status_effect(STATUS_EFFECT_FAKE_VIRUS)
|
||||
fake_virus_victims -= hypochondriac
|
||||
|
||||
//then we do light one-message victims who simply cough or whatever once (have to repeat the process since the last operation modified our candidates list)
|
||||
defacto_min = min(5, LAZYLEN(fake_virus_victims))
|
||||
if(defacto_min)
|
||||
for(var/i=1; i<=rand(1,defacto_min); i++)
|
||||
var/mob/living/carbon/human/onecoughman = pick(fake_virus_victims)
|
||||
if(prob(25))//1/4 odds to get a spooky message instead of coughing out loud
|
||||
addtimer(CALLBACK(GLOBAL_PROC, .proc/to_chat, onecoughman, "<span class='warning'>[pick("Your head hurts.", "Your head pounds.")]</span>"), rand(30,150))
|
||||
else
|
||||
addtimer(CALLBACK(onecoughman, .mob/proc/emote, pick("cough", "sniff", "sneeze")), rand(30,150))//deliver the message with a slightly randomized time interval so there arent multiple people coughing at the exact same time
|
||||
fake_virus_victims -= onecoughman
|
||||
@@ -0,0 +1,117 @@
|
||||
/datum/round_event_control/fugitives
|
||||
name = "Spawn Fugitives"
|
||||
typepath = /datum/round_event/ghost_role/fugitives
|
||||
max_occurrences = 1
|
||||
min_players = 20
|
||||
earliest_start = 30 MINUTES //deadchat sink, lets not even consider it early on.
|
||||
gamemode_blacklist = list("nuclear")
|
||||
|
||||
/datum/round_event/ghost_role/fugitives
|
||||
minimum_required = 1
|
||||
role_name = "fugitive"
|
||||
fakeable = FALSE
|
||||
|
||||
/datum/round_event/ghost_role/fugitives/spawn_role()
|
||||
var/list/possible_spawns = list()//Some xeno spawns are in some spots that will instantly kill the refugees, like atmos
|
||||
for(var/turf/X in GLOB.xeno_spawn)
|
||||
if(istype(X.loc, /area/maintenance))
|
||||
possible_spawns += X
|
||||
if(!possible_spawns.len)
|
||||
message_admins("No valid spawn locations found, aborting...")
|
||||
return MAP_ERROR
|
||||
var/turf/landing_turf = pick(possible_spawns)
|
||||
var/list/possible_backstories = list()
|
||||
var/list/candidates = get_candidates(ROLE_TRAITOR, null, ROLE_TRAITOR)
|
||||
if(candidates.len >= 1) //solo refugees
|
||||
if(prob(30))
|
||||
possible_backstories.Add("waldo") //less common as it comes with magicks and is kind of immershun shattering
|
||||
else //For accurate deadchat feedback
|
||||
minimum_required = 4
|
||||
if(candidates.len >= 4)//group refugees
|
||||
possible_backstories.Add("prisoner", "cultist", "synth")
|
||||
if(!possible_backstories.len)
|
||||
return NOT_ENOUGH_PLAYERS
|
||||
|
||||
var/backstory = pick(possible_backstories)
|
||||
var/member_size = 3
|
||||
var/leader
|
||||
switch(backstory)
|
||||
if("synth")
|
||||
leader = pick_n_take(candidates)
|
||||
if("waldo")
|
||||
member_size = 0 //solo refugees have no leader so the member_size gets bumped to one a bit later
|
||||
var/list/members = list()
|
||||
var/list/spawned_mobs = list()
|
||||
if(isnull(leader))
|
||||
member_size++ //if there is no leader role, then the would be leader is a normal member of the team.
|
||||
|
||||
for(var/i in 1 to member_size)
|
||||
members += pick_n_take(candidates)
|
||||
|
||||
for(var/mob/dead/selected in members)
|
||||
var/mob/living/carbon/human/S = gear_fugitive(selected, landing_turf, backstory)
|
||||
spawned_mobs += S
|
||||
if(!isnull(leader))
|
||||
gear_fugitive_leader(leader, landing_turf, backstory)
|
||||
|
||||
//after spawning
|
||||
playsound(src, 'sound/weapons/emitter.ogg', 50, TRUE)
|
||||
new /obj/item/storage/toolbox/mechanical(landing_turf) //so they can actually escape maint
|
||||
addtimer(CALLBACK(src, .proc/spawn_hunters), 10 MINUTES)
|
||||
role_name = "fugitive hunter"
|
||||
return SUCCESSFUL_SPAWN
|
||||
|
||||
/datum/round_event/ghost_role/fugitives/proc/gear_fugitive(mob/dead/selected, turf/landing_turf, backstory) //spawns normal fugitive
|
||||
var/datum/mind/player_mind = new /datum/mind(selected.key)
|
||||
player_mind.active = TRUE
|
||||
var/mob/living/carbon/human/S = new(landing_turf)
|
||||
player_mind.transfer_to(S)
|
||||
player_mind.assigned_role = "Fugitive"
|
||||
player_mind.special_role = "Fugitive"
|
||||
player_mind.add_antag_datum(/datum/antagonist/fugitive)
|
||||
var/datum/antagonist/fugitive/fugitiveantag = player_mind.has_antag_datum(/datum/antagonist/fugitive)
|
||||
INVOKE_ASYNC(fugitiveantag, /datum/antagonist/fugitive.proc/greet, backstory) //some fugitives have a sleep on their greet, so we don't want to stop the entire antag granting proc with fluff
|
||||
|
||||
switch(backstory)
|
||||
if("prisoner")
|
||||
S.equipOutfit(/datum/outfit/prisoner)
|
||||
if("cultist")
|
||||
S.equipOutfit(/datum/outfit/yalp_cultist)
|
||||
if("waldo")
|
||||
S.equipOutfit(/datum/outfit/waldo)
|
||||
if("synth")
|
||||
S.equipOutfit(/datum/outfit/synthetic)
|
||||
message_admins("[ADMIN_LOOKUPFLW(S)] has been made into a Fugitive by an event.")
|
||||
log_game("[key_name(S)] was spawned as a Fugitive by an event.")
|
||||
spawned_mobs += S
|
||||
return S
|
||||
|
||||
//special spawn for one member. it can be used for a special mob or simply to give one normal member special items.
|
||||
/datum/round_event/ghost_role/fugitives/proc/gear_fugitive_leader(mob/dead/leader, turf/landing_turf, backstory)
|
||||
var/datum/mind/player_mind = new /datum/mind(leader.key)
|
||||
player_mind.active = TRUE
|
||||
//if you want to add a fugitive with a special leader in the future, make this switch with the backstory
|
||||
var/mob/living/carbon/human/S = gear_fugitive(leader, landing_turf, backstory)
|
||||
var/obj/item/choice_beacon/augments/A = new(S)
|
||||
S.put_in_hands(A)
|
||||
new /obj/item/autosurgeon(landing_turf)
|
||||
|
||||
//security team gets called in after 10 minutes of prep to find the refugees
|
||||
/datum/round_event/ghost_role/fugitives/proc/spawn_hunters()
|
||||
var/backstory = pick("space cop", "russian", "bounty hunter")
|
||||
var/datum/map_template/shuttle/ship
|
||||
if(backstory == "space cop")
|
||||
ship = new /datum/map_template/shuttle/hunter/space_cop
|
||||
else if (backstory == "russian")
|
||||
ship = new /datum/map_template/shuttle/hunter/russian
|
||||
else
|
||||
ship = new /datum/map_template/shuttle/hunter/bounty
|
||||
var/x = rand(TRANSITIONEDGE,world.maxx - TRANSITIONEDGE - ship.width)
|
||||
var/y = rand(TRANSITIONEDGE,world.maxy - TRANSITIONEDGE - ship.height)
|
||||
var/z = SSmapping.empty_space.z_value
|
||||
var/turf/T = locate(x,y,z)
|
||||
if(!T)
|
||||
CRASH("Fugitive Hunters (Created from fugitive event) found no turf to load in")
|
||||
if(!ship.load(T))
|
||||
CRASH("Loading [backstory] ship failed!")
|
||||
priority_announce("Unidentified ship detected near the station.")
|
||||
@@ -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)
|
||||
|
||||
@@ -0,0 +1,99 @@
|
||||
///Spawns a cargo pod containing a random cargo supply pack on a random area of the station
|
||||
/datum/round_event_control/stray_cargo
|
||||
name = "Stray Cargo Pod"
|
||||
typepath = /datum/round_event/stray_cargo
|
||||
weight = 20
|
||||
max_occurrences = 4
|
||||
earliest_start = 10 MINUTES
|
||||
|
||||
///Spawns a cargo pod containing a random cargo supply pack on a random area of the station
|
||||
/datum/round_event/stray_cargo
|
||||
var/area/impact_area ///Randomly picked area
|
||||
var/list/possible_pack_types = list() ///List of possible supply packs dropped in the pod, if empty picks from the cargo list
|
||||
var/static/list/stray_spawnable_supply_packs = list() ///List of default spawnable supply packs, filtered from the cargo list
|
||||
|
||||
/datum/round_event/stray_cargo/announce(fake)
|
||||
priority_announce("Stray cargo pod detected on long-range scanners. Expected location of impact: [impact_area.name].", "Collision Alert")
|
||||
|
||||
/**
|
||||
* Tries to find a valid area, throws an error if none are found
|
||||
* Also randomizes the start timer
|
||||
*/
|
||||
/datum/round_event/stray_cargo/setup()
|
||||
startWhen = rand(20, 40)
|
||||
impact_area = find_event_area()
|
||||
if(!impact_area)
|
||||
CRASH("No valid areas for cargo pod found.")
|
||||
var/list/turf_test = get_area_turfs(impact_area)
|
||||
if(!turf_test.len)
|
||||
CRASH("Stray Cargo Pod : No valid turfs found for [impact_area] - [impact_area.type]")
|
||||
|
||||
if(!stray_spawnable_supply_packs.len)
|
||||
stray_spawnable_supply_packs = SSshuttle.supply_packs.Copy()
|
||||
for(var/pack in stray_spawnable_supply_packs)
|
||||
var/datum/supply_pack/pack_type = pack
|
||||
if(initial(pack_type.special))
|
||||
stray_spawnable_supply_packs -= pack
|
||||
|
||||
///Spawns a random supply pack, puts it in a pod, and spawns it on a random tile of the selected area
|
||||
/datum/round_event/stray_cargo/start()
|
||||
var/list/turf/valid_turfs = get_area_turfs(impact_area)
|
||||
//Only target non-dense turfs to prevent wall-embedded pods
|
||||
for(var/i in valid_turfs)
|
||||
var/turf/T = i
|
||||
if(T.density)
|
||||
valid_turfs -= T
|
||||
var/turf/LZ = pick(valid_turfs)
|
||||
var/pack_type
|
||||
if(possible_pack_types.len)
|
||||
pack_type = pick(possible_pack_types)
|
||||
else
|
||||
pack_type = pick(stray_spawnable_supply_packs)
|
||||
var/datum/supply_pack/SP = new pack_type
|
||||
var/obj/structure/closet/crate/crate = SP.generate(null)
|
||||
crate.locked = FALSE //Unlock secure crates
|
||||
crate.update_icon()
|
||||
var/obj/structure/closet/supplypod/pod = make_pod()
|
||||
crate.forceMove(pod)
|
||||
new /obj/effect/abstract/DPtarget(LZ, pod)
|
||||
|
||||
///Handles the creation of the pod, in case it needs to be modified beforehand
|
||||
/datum/round_event/stray_cargo/proc/make_pod()
|
||||
var/obj/structure/closet/supplypod/S = new
|
||||
return S
|
||||
|
||||
///Picks an area that wouldn't risk critical damage if hit by a pod explosion
|
||||
/datum/round_event/stray_cargo/proc/find_event_area()
|
||||
var/static/list/allowed_areas
|
||||
if(!allowed_areas)
|
||||
///Places that shouldn't explode
|
||||
var/list/safe_area_types = typecacheof(list(
|
||||
/area/ai_monitored/turret_protected/ai,
|
||||
/area/ai_monitored/turret_protected/ai_upload,
|
||||
/area/engine,
|
||||
/area/shuttle)
|
||||
)
|
||||
|
||||
///Subtypes from the above that actually should explode.
|
||||
var/list/unsafe_area_subtypes = typecacheof(list(/area/engine/break_room))
|
||||
allowed_areas = make_associative(GLOB.the_station_areas) - safe_area_types + unsafe_area_subtypes
|
||||
var/list/possible_areas = typecache_filter_list(GLOB.sortedAreas,allowed_areas)
|
||||
if (length(possible_areas))
|
||||
return pick(possible_areas)
|
||||
|
||||
///A rare variant that drops a crate containing syndicate uplink items
|
||||
/datum/round_event_control/stray_cargo/syndicate
|
||||
name = "Stray Syndicate Cargo Pod"
|
||||
typepath = /datum/round_event/stray_cargo/syndicate
|
||||
weight = 6
|
||||
max_occurrences = 1
|
||||
earliest_start = 30 MINUTES
|
||||
|
||||
/datum/round_event/stray_cargo/syndicate
|
||||
possible_pack_types = list(/datum/supply_pack/misc/syndicate)
|
||||
|
||||
///Apply the syndicate pod skin
|
||||
/datum/round_event/stray_cargo/syndicate/make_pod()
|
||||
var/obj/structure/closet/supplypod/S = new
|
||||
S.setStyle(STYLE_SYNDICATE)
|
||||
return S
|
||||
@@ -140,22 +140,6 @@
|
||||
typepath = /datum/round_event/vent_clog/plasma_decon
|
||||
max_occurrences = 0
|
||||
|
||||
/datum/round_event_control/vent_clog/female
|
||||
name = "Clogged Vents; Girlcum"
|
||||
typepath = /datum/round_event/vent_clog/female
|
||||
max_occurrences = 0
|
||||
|
||||
/datum/round_event/vent_clog/female
|
||||
reagentsAmount = 100
|
||||
|
||||
/datum/round_event_control/vent_clog/male
|
||||
name = "Clogged Vents: Semen"
|
||||
typepath = /datum/round_event/vent_clog/male
|
||||
max_occurrences = 0
|
||||
|
||||
/datum/round_event/vent_clog/male
|
||||
reagentsAmount = 100
|
||||
|
||||
/datum/round_event/vent_clog/beer/announce()
|
||||
priority_announce("The scrubbers network is experiencing an unexpected surge of pressurized beer. Some ejection of contents may occur.", "Atmospherics alert")
|
||||
|
||||
@@ -171,36 +155,6 @@
|
||||
foam.start()
|
||||
CHECK_TICK
|
||||
|
||||
/datum/round_event/vent_clog/male/announce()
|
||||
priority_announce("The scrubbers network is experiencing a backpressure surge. Some ejaculation of contents may occur.", "Atmospherics alert")
|
||||
|
||||
/datum/round_event/vent_clog/male/start()
|
||||
for(var/obj/machinery/atmospherics/components/unary/vent in vents)
|
||||
if(vent && vent.loc && !vent.welded)
|
||||
var/datum/reagents/R = new/datum/reagents(1000)
|
||||
R.my_atom = vent
|
||||
R.add_reagent(/datum/reagent/consumable/semen, reagentsAmount)
|
||||
|
||||
var/datum/effect_system/foam_spread/foam = new
|
||||
foam.set_up(200, get_turf(vent), R)
|
||||
foam.start()
|
||||
CHECK_TICK
|
||||
|
||||
/datum/round_event/vent_clog/female/announce()
|
||||
priority_announce("The scrubbers network is experiencing a backpressure squirt. Some ejection of contents may occur.", "Atmospherics alert")
|
||||
|
||||
/datum/round_event/vent_clog/female/start()
|
||||
for(var/obj/machinery/atmospherics/components/unary/vent in vents)
|
||||
if(vent && vent.loc && !vent.welded)
|
||||
var/datum/reagents/R = new/datum/reagents(1000)
|
||||
R.my_atom = vent
|
||||
R.add_reagent(/datum/reagent/consumable/femcum, reagentsAmount)
|
||||
|
||||
var/datum/effect_system/foam_spread/foam = new
|
||||
foam.set_up(200, get_turf(vent), R)
|
||||
foam.start()
|
||||
CHECK_TICK
|
||||
|
||||
/datum/round_event/vent_clog/plasma_decon/announce()
|
||||
priority_announce("We are deploying an experimental plasma decontamination system. Please stand away from the vents and do not breathe the smoke that comes out.", "Central Command Update")
|
||||
|
||||
|
||||
@@ -0,0 +1,15 @@
|
||||
/datum/round_event_control/wisdomcow
|
||||
name = "Wisdom cow"
|
||||
typepath = /datum/round_event/wisdomcow
|
||||
max_occurrences = 1
|
||||
weight = 20
|
||||
|
||||
/datum/round_event/wisdomcow/announce(fake)
|
||||
priority_announce("A wise cow has been spotted in the area. Be sure to ask for her advice.", "Nanotrasen Cow Ranching Agency")
|
||||
|
||||
/datum/round_event/wisdomcow/start()
|
||||
var/turf/targetloc = get_random_station_turf()
|
||||
new /mob/living/simple_animal/cow/wisdom(targetloc)
|
||||
var/datum/effect_system/smoke_spread/smoke = new
|
||||
smoke.set_up(1, targetloc)
|
||||
smoke.start()
|
||||
@@ -0,0 +1,46 @@
|
||||
/datum/round_event_control/wizard/embedpocalypse
|
||||
name = "Make Everything Embeddable"
|
||||
weight = 2
|
||||
typepath = /datum/round_event/wizard/embedpocalypse
|
||||
max_occurrences = 1
|
||||
earliest_start = 0 MINUTES
|
||||
|
||||
/datum/round_event/wizard/embedpocalypse/start()
|
||||
for(var/obj/item/I in world)
|
||||
CHECK_TICK
|
||||
|
||||
if(!(I.flags_1 & INITIALIZED_1))
|
||||
continue
|
||||
|
||||
if(!I.embedding || I.embedding == EMBED_HARMLESS)
|
||||
I.embedding = EMBED_POINTY
|
||||
I.updateEmbedding()
|
||||
I.name = "pointy [I.name]"
|
||||
|
||||
GLOB.embedpocalypse = TRUE
|
||||
GLOB.stickpocalypse = FALSE // embedpocalypse takes precedence over stickpocalypse
|
||||
|
||||
/datum/round_event_control/wizard/embedpocalypse/sticky
|
||||
name = "Make Everything Sticky"
|
||||
weight = 6
|
||||
typepath = /datum/round_event/wizard/embedpocalypse/sticky
|
||||
max_occurrences = 1
|
||||
earliest_start = 0 MINUTES
|
||||
|
||||
/datum/round_event_control/wizard/embedpocalypse/sticky/canSpawnEvent(players_amt, gamemode)
|
||||
if(GLOB.embedpocalypse)
|
||||
return FALSE
|
||||
|
||||
/datum/round_event/wizard/embedpocalypse/sticky/start()
|
||||
for(var/obj/item/I in world)
|
||||
CHECK_TICK
|
||||
|
||||
if(!(I.flags_1 & INITIALIZED_1))
|
||||
continue
|
||||
|
||||
if(!I.embedding)
|
||||
I.embedding = EMBED_HARMLESS
|
||||
I.updateEmbedding()
|
||||
I.name = "sticky [I.name]"
|
||||
|
||||
GLOB.stickpocalypse = TRUE
|
||||
@@ -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()
|
||||
|
||||
@@ -315,6 +315,15 @@
|
||||
slice_path = /obj/item/reagent_containers/food/snacks/meat/rawcutlet/gondola
|
||||
foodtype = RAW | MEAT
|
||||
|
||||
/obj/item/reagent_containers/food/snacks/meat/slab/wisdomcow
|
||||
name = "wisdom cow meat"
|
||||
desc = "The meat from the legendary creature known as the wisdom cow. You monster."
|
||||
list_reagents = list(/datum/reagent/consumable/nutriment = 3, /datum/reagent/medicine/liquid_wisdom = 5)
|
||||
tastes = list("meat" = 1, "wisdom" = 5)
|
||||
filling_color = "#18e3ca"
|
||||
cooked_type = /obj/item/reagent_containers/food/snacks/meat/steak/wisdomcow
|
||||
slice_path = /obj/item/reagent_containers/food/snacks/meat/rawcutlet/wisdomcow
|
||||
|
||||
////////////////////////////////////// MEAT STEAKS ///////////////////////////////////////////////////////////
|
||||
|
||||
|
||||
@@ -374,6 +383,10 @@
|
||||
name = "gondola steak"
|
||||
tastes = list("meat" = 1, "tranquility" = 1)
|
||||
|
||||
/obj/item/reagent_containers/food/snacks/meat/steak/wisdomcow
|
||||
name = "wisdom cow steak"
|
||||
tastes = list("meat" = 1, "wisdom" = 5)
|
||||
|
||||
//////////////////////////////// MEAT CUTLETS ///////////////////////////////////////////////////////
|
||||
|
||||
//Raw cutlets
|
||||
@@ -441,6 +454,11 @@
|
||||
cooked_type = /obj/item/reagent_containers/food/snacks/meat/cutlet/gondola
|
||||
tastes = list("meat" = 1, "tranquility" = 1)
|
||||
|
||||
/obj/item/reagent_containers/food/snacks/meat/rawcutlet/wisdomcow
|
||||
name = "raw wisdom cow cutlet"
|
||||
cooked_type = /obj/item/reagent_containers/food/snacks/meat/cutlet/wisdomcow
|
||||
tastes = list("meat" = 1, "wisdom" = 5)
|
||||
|
||||
//Cooked cutlets
|
||||
|
||||
/obj/item/reagent_containers/food/snacks/meat/cutlet
|
||||
@@ -488,3 +506,7 @@
|
||||
/obj/item/reagent_containers/food/snacks/meat/cutlet/chicken
|
||||
name = "chicken cutlet"
|
||||
tastes = list("chicken" = 1)
|
||||
|
||||
/obj/item/reagent_containers/food/snacks/meat/cutlet/wisdomcow
|
||||
name = "wisdom cow cutlet"
|
||||
tastes = list("meat" = 1, "wisdom" = 5)
|
||||
|
||||
@@ -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
|
||||
@@ -421,11 +487,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")
|
||||
|
||||
@@ -195,7 +195,7 @@
|
||||
/obj/item/reagent_containers/food/snacks/grown/firelemon/ex_act(severity)
|
||||
qdel(src) //Ensuring that it's deleted by its own explosion
|
||||
|
||||
/obj/item/reagent_containers/food/snacks/grown/firelemon/proc/prime()
|
||||
/obj/item/reagent_containers/food/snacks/grown/firelemon/proc/prime(mob/living/lanced_by)
|
||||
switch(seed.potency) //Combustible lemons are alot like IEDs, lots of flame, very little bang.
|
||||
if(0 to 30)
|
||||
update_mob()
|
||||
|
||||
@@ -223,7 +223,7 @@
|
||||
/obj/item/reagent_containers/food/snacks/grown/cherry_bomb/ex_act(severity)
|
||||
qdel(src) //Ensuring that it's deleted by its own explosion. Also prevents mass chain reaction with piles of cherry bombs
|
||||
|
||||
/obj/item/reagent_containers/food/snacks/grown/cherry_bomb/proc/prime()
|
||||
/obj/item/reagent_containers/food/snacks/grown/cherry_bomb/proc/prime(mob/living/lanced_by)
|
||||
icon_state = "cherry_bomb_lit"
|
||||
playsound(src, 'sound/effects/fuse.ogg', seed.potency, 0)
|
||||
addtimer(CALLBACK(src, /obj/item/reagent_containers/food/snacks/grown/cherry_bomb/proc/detonate), rand(50, 100))
|
||||
|
||||
@@ -283,10 +283,8 @@
|
||||
|
||||
/obj/item/integrated_circuit/arithmetic/square_root/do_work()
|
||||
var/result = 0
|
||||
for(var/k in 2 to inputs.len)
|
||||
var/I = get_pin_data(IC_INPUT, k)
|
||||
if(isnum(I))
|
||||
result += sqrt(I)
|
||||
var/I = get_pin_data(IC_INPUT, 1)
|
||||
result = sqrt(I)
|
||||
|
||||
set_pin_data(IC_OUTPUT, 1, result)
|
||||
push_data()
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -1,21 +1,27 @@
|
||||
/datum/minimap
|
||||
var/name
|
||||
var/name = "minimap"
|
||||
var/icon/overlay_icon
|
||||
// The map icons
|
||||
var/icon/map_icon
|
||||
var/icon/meta_icon
|
||||
var/icon/overlay_icon
|
||||
|
||||
var/list/color_area_names = list()
|
||||
|
||||
var/minx
|
||||
var/maxx
|
||||
var/miny
|
||||
var/maxy
|
||||
var/z_level
|
||||
var/id = 0
|
||||
var/static/next_id = 0
|
||||
|
||||
/datum/minimap/New(z, x1 = 1, y1 = 1, x2 = world.maxx, y2 = world.maxy, name)
|
||||
var/z_level
|
||||
var/id = ""
|
||||
|
||||
/datum/minimap/New(z, x1 = 1, y1 = 1, x2 = world.maxx, y2 = world.maxy, name = "minimap")
|
||||
if(!z)
|
||||
CRASH("ERROR: new minimap requested without z level") //CRASH to halt the operatio
|
||||
|
||||
src.name = name
|
||||
id = ++next_id
|
||||
z_level = z
|
||||
id = "[md5("[z_level]" + src.name + REF(src))]" //use it's own md5 as a special identifier
|
||||
|
||||
var/crop_x1 = x2
|
||||
var/crop_x2 = x1
|
||||
@@ -25,10 +31,11 @@
|
||||
// do the generating
|
||||
map_icon = new('html/blank.png')
|
||||
meta_icon = new('html/blank.png')
|
||||
map_icon.Scale(x2-x1+1, y2-y1+1) // arrays start at 1
|
||||
meta_icon.Scale(x2-x1+1, y2-y1+1)
|
||||
map_icon.Scale(x2 - x1 + 1, y2 - y1 + 1) // arrays start at 1
|
||||
meta_icon.Scale(x2 - x1 + 1, y2 - y1 + 1)
|
||||
|
||||
var/list/area_to_color = list()
|
||||
for(var/turf/T in block(locate(x1,y1,z),locate(x2,y2,z)))
|
||||
for(var/turf/T in block(locate(x1, y1, z_level), locate(x2, y2, z_level)))
|
||||
var/area/A = T.loc
|
||||
var/img_x = T.x - x1 + 1 // arrays start at 1
|
||||
var/img_y = T.y - y1 + 1
|
||||
@@ -37,21 +44,26 @@
|
||||
crop_x2 = max(crop_x2, T.x)
|
||||
crop_y1 = min(crop_y1, T.y)
|
||||
crop_y2 = max(crop_y2, T.y)
|
||||
|
||||
var/meta_color = area_to_color[A]
|
||||
if(!meta_color)
|
||||
meta_color = rgb(rand(0,255),rand(0,255),rand(0,255)) // technically conflicts could happen but it's like very unlikely and it's not that big of a deal if one happens
|
||||
meta_color = rgb(rand(0, 255), rand(0, 255), rand(0, 255)) // technically conflicts could happen but it's like very unlikely and it's not that big of a deal if one happens
|
||||
area_to_color[A] = meta_color
|
||||
color_area_names[meta_color] = A.name
|
||||
meta_icon.DrawBox(meta_color, img_x, img_y)
|
||||
|
||||
if(istype(T, /turf/closed/wall))
|
||||
map_icon.DrawBox("#000000", img_x, img_y)
|
||||
|
||||
else if(!istype(A, /area/space))
|
||||
var/color = A.minimap_color || "#FF00FF"
|
||||
if(locate(/obj/machinery/power/solar) in T)
|
||||
color = "#02026a"
|
||||
|
||||
if((locate(/obj/effect/spawner/structure/window) in T) || (locate(/obj/structure/grille) in T))
|
||||
color = BlendRGB(color, "#000000", 0.5)
|
||||
map_icon.DrawBox(color, img_x, img_y)
|
||||
|
||||
map_icon.Crop(crop_x1, crop_y1, crop_x2, crop_y2)
|
||||
meta_icon.Crop(crop_x1, crop_y1, crop_x2, crop_y2)
|
||||
minx = crop_x1
|
||||
@@ -60,14 +72,17 @@
|
||||
maxy = crop_y2
|
||||
overlay_icon = new(map_icon)
|
||||
overlay_icon.Scale(16, 16)
|
||||
|
||||
/datum/minimap/proc/send(mob/user)
|
||||
//we're done baking, now we ship it.
|
||||
register_asset("minimap-[id].png", map_icon)
|
||||
register_asset("minimap-[id]-meta.png", meta_icon)
|
||||
send_asset_list(user, list("minimap-[id].png" = map_icon, "minimap-[id]-meta.png" = meta_icon), verify=FALSE)
|
||||
|
||||
/datum/minimap/proc/send(mob/user)
|
||||
if(!id)
|
||||
CRASH("ERROR: send called, but the minimap id is null/missing. ID: [id]")
|
||||
send_asset_list(user, list("minimap-[id].png" = map_icon, "minimap-[id]-meta.png" = meta_icon))
|
||||
|
||||
/datum/minimap_group
|
||||
var/list/minimaps
|
||||
var/list/minimaps = list()
|
||||
var/static/next_id = 0
|
||||
var/id
|
||||
var/name
|
||||
@@ -75,46 +90,62 @@
|
||||
/datum/minimap_group/New(list/maps, name)
|
||||
id = ++next_id
|
||||
src.name = name
|
||||
minimaps = maps || list()
|
||||
if(maps)
|
||||
minimaps = maps
|
||||
|
||||
/datum/minimap_group/proc/show(mob/user)
|
||||
if(!length(minimaps))
|
||||
to_chat(user, "<span class='boldwarning'>ERROR: Attempted to access an empty datum/minimap_group. This should probably not happen.</span>")
|
||||
return
|
||||
|
||||
var/list/datas = list()
|
||||
var/list/info = list()
|
||||
var/datum/minimap/first_map = minimaps[1]
|
||||
for(var/i in 1 to length(minimaps))
|
||||
|
||||
for(var/i in 1 to length(minimaps))// OLD: for(var/i in 1 to length(minimaps))
|
||||
var/datum/minimap/M = minimaps[i]
|
||||
M.send(user)
|
||||
info += "<img src='minimap-[M.id].png' id='map-[i]'><img src='minimap-[M.id]-meta.png' style='display: none' id='map-[i]-meta'><div id='label-[i]'></div>"
|
||||
info += {"
|
||||
<div class="block">
|
||||
<div> <!-- The div is in here to fit it both in the block div -->
|
||||
<img id='map-[i]' src='minimap-[M.id].png' />
|
||||
<img id='map-[i]-meta' src='minimap-[M.id]-meta.png' style='display: none' />
|
||||
</div>
|
||||
<div class="statusDisplay" id='label-[i]'></div>
|
||||
</div>
|
||||
"}
|
||||
datas += json_encode(M.color_area_names);
|
||||
info = info.Join()
|
||||
|
||||
var/html = {"
|
||||
<!DOCTYPE html>
|
||||
<HTML>
|
||||
<HEAD>
|
||||
<meta http-equiv='X-UA-Compatible' content='IE=edge'>
|
||||
<meta http-equiv='Content-Type' content='text/html; charset=UTF-8'>
|
||||
<script>
|
||||
function hexify(num) {
|
||||
if(!num) num = 0;
|
||||
num = num.toString(16);
|
||||
if(num.length == 1) num = "0" + num;
|
||||
return num;
|
||||
}
|
||||
window.onload = function() {
|
||||
var datas = \[[jointext(datas, ",")]]
|
||||
if(window.HTMLCanvasElement) {
|
||||
for(var i = 0; i < [minimaps.len]; i++) {
|
||||
(function() {
|
||||
info = info.Join()
|
||||
//this is bad. Too bad!
|
||||
var/headerJS = {"
|
||||
<script>
|
||||
function hexify(num) {
|
||||
if(!num){
|
||||
num = 0;
|
||||
}
|
||||
num = num.toString(16);
|
||||
if(num.length == 1){
|
||||
num = "0" + num;
|
||||
}
|
||||
return num;
|
||||
}
|
||||
window.onload = function() {
|
||||
var datas = \[[jointext(datas, ",")]]
|
||||
if(!window.HTMLCanvasElement){
|
||||
//something has gone horribly wrong!
|
||||
return false
|
||||
}
|
||||
for(var i = 0; i < [length(minimaps)]; i++){
|
||||
//the fuck is this wrapped?
|
||||
var data = datas\[i];
|
||||
var img = document.getElementById("map-" + (i+1));
|
||||
if(!img) return;
|
||||
var img = document.getElementById("map-" + (i + 1));
|
||||
if(!img){
|
||||
return; //if it does not exist, it means it's done!
|
||||
}
|
||||
var canvas = document.createElement("canvas");
|
||||
canvas.width = img.width * 2;
|
||||
canvas.height = img.height * 2;
|
||||
|
||||
var ctx = canvas.getContext('2d');
|
||||
ctx.msImageSmoothingEnabled = false;
|
||||
ctx.drawImage(img, 0, 0, canvas.width, canvas.height);
|
||||
@@ -123,9 +154,10 @@ window.onload = function() {
|
||||
ctx.canvas.width = img.width;
|
||||
ctx.canvas.height = img.height;
|
||||
ctx.drawImage(document.getElementById("map-" + (i+1) + "-meta"), 0, 0);
|
||||
|
||||
var imagedata = ctx.getImageData(0, 0, img.width, img.height);
|
||||
var label = document.getElementById("label-" + (i+1));
|
||||
canvas.onmousemove = function(e) {
|
||||
canvas.onmousemove = function(e){
|
||||
var rect = canvas.getBoundingClientRect();
|
||||
var x = Math.floor(e.offsetX * img.width / rect.width);
|
||||
var y = Math.floor(e.offsetY * img.height / rect.height);
|
||||
@@ -134,23 +166,23 @@ window.onload = function() {
|
||||
label.textContent = data\[color];
|
||||
canvas.title = data\[color];
|
||||
}
|
||||
canvas.onmouseout = function(e) {
|
||||
label.textContent = "";
|
||||
canvas.onmouseout = function(e){
|
||||
canvas.title = "";
|
||||
}
|
||||
})();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
</script>
|
||||
<STYLE>
|
||||
img, canvas {
|
||||
width: 100%
|
||||
}
|
||||
</STYLE>
|
||||
<TITLE>[name]</TITLE>
|
||||
</HEAD>
|
||||
<BODY>[info]</BODY>
|
||||
</HTML>"}
|
||||
</script>
|
||||
<style>
|
||||
img, canvas {
|
||||
width: 100%;
|
||||
background-color: white;
|
||||
}
|
||||
</style>
|
||||
"}
|
||||
|
||||
user << browse(html, "window=minimap_[id];size=768x[round(768 / first_map.map_icon.Width() * first_map.map_icon.Height() + 50)]")
|
||||
var/datum/browser/popup = new(user, "minimap_[id]", name, 500, 700)
|
||||
popup.add_head_content(headerJS) //set the head
|
||||
popup.set_content(info)
|
||||
var/datum/minimap/MICO = minimaps[1]
|
||||
popup.set_title_image(MICO.overlay_icon)
|
||||
popup.open(FALSE)
|
||||
|
||||
@@ -11,7 +11,7 @@
|
||||
desc = "It's watching you suspiciously."
|
||||
|
||||
/obj/structure/closet/crate/necropolis/tendril/PopulateContents()
|
||||
var/loot = rand(1,28)
|
||||
var/loot = rand(1,29)
|
||||
switch(loot)
|
||||
if(1)
|
||||
new /obj/item/shared_storage/red(src)
|
||||
@@ -77,6 +77,11 @@
|
||||
new /obj/item/bedsheet/cult(src)
|
||||
if(28)
|
||||
new /obj/item/clothing/neck/necklace/memento_mori(src)
|
||||
if(29)
|
||||
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)
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user