@@ -84,7 +84,7 @@ GLOBAL_LIST(round_end_notifiees)
|
||||
if(!SSticker.IsRoundInProgress() && SSticker.HasRoundStarted())
|
||||
return "[sender.mention], the round has already ended!"
|
||||
LAZYINITLIST(GLOB.round_end_notifiees)
|
||||
GLOB.round_end_notifiees["<@[sender.mention]>"] = TRUE
|
||||
GLOB.round_end_notifiees[sender.mention] = TRUE
|
||||
return "I will notify [sender.mention] when the round ends."
|
||||
|
||||
/datum/tgs_chat_command/sdql
|
||||
|
||||
@@ -126,7 +126,7 @@
|
||||
L.forceMove(LA)
|
||||
L.hallucination = 0
|
||||
to_chat(L, "<span class='reallybig redtext'>The battle is won. Your bloodlust subsides.</span>")
|
||||
for(var/obj/item/twohanded/required/chainsaw/doomslayer/chainsaw in L)
|
||||
for(var/obj/item/chainsaw/doomslayer/chainsaw in L)
|
||||
qdel(chainsaw)
|
||||
else
|
||||
to_chat(L, "You are not yet worthy of passing. Drag a severed head to the barrier to be allowed entry to the hall of champions.")
|
||||
|
||||
@@ -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()
|
||||
|
||||
@@ -234,3 +234,7 @@
|
||||
for(var/turf/T in v)
|
||||
. += T
|
||||
return pick(.)
|
||||
|
||||
/proc/__nan()
|
||||
var/list/L = json_decode("{\"value\":NaN}")
|
||||
return L["value"]
|
||||
|
||||
@@ -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
|
||||
@@ -82,6 +94,9 @@ GLOBAL_LIST_EMPTY(antagonists)
|
||||
if(skill_modifiers)
|
||||
for(var/A in skill_modifiers)
|
||||
ADD_SINGLETON_SKILL_MODIFIER(owner, A, type)
|
||||
var/datum/skill_modifier/job/M = GLOB.skill_modifiers[GET_SKILL_MOD_ID(A, type)]
|
||||
if(istype(M))
|
||||
M.name = "[name] Training"
|
||||
SEND_SIGNAL(owner.current, COMSIG_MOB_ANTAG_ON_GAIN, src)
|
||||
|
||||
/datum/antagonist/proc/is_banned(mob/M)
|
||||
|
||||
@@ -0,0 +1,12 @@
|
||||
/obj/structure/fluff/iced_abductor ///Unless more non-machine ayy structures made, it will stay in fluff.
|
||||
name = "Mysterious Block of Ice"
|
||||
desc = "A shadowy figure lies in this sturdy-looking block of ice. Who knows where it came from?"
|
||||
icon = 'icons/effects/freeze.dmi'
|
||||
icon_state = "ice_ayy"
|
||||
density = TRUE
|
||||
deconstructible = FALSE
|
||||
|
||||
/obj/structure/fluff/iced_abductor/Destroy()
|
||||
var/turf/T = get_turf(src)
|
||||
new /obj/effect/mob_spawn/human/abductor(T)
|
||||
. = ..()
|
||||
@@ -103,7 +103,9 @@
|
||||
factory.spores += src
|
||||
. = ..()
|
||||
|
||||
/mob/living/simple_animal/hostile/blob/blobspore/Life()
|
||||
/mob/living/simple_animal/hostile/blob/blobspore/BiologicalLife(seconds, times_fired)
|
||||
if(!(. = ..()))
|
||||
return
|
||||
if(!is_zombie && isturf(src.loc))
|
||||
for(var/mob/living/carbon/human/H in view(src,1)) //Only for corpse right next to/on same tile
|
||||
if(H.stat == DEAD)
|
||||
@@ -111,7 +113,6 @@
|
||||
break
|
||||
if(factory && z != factory.z)
|
||||
death()
|
||||
..()
|
||||
|
||||
/mob/living/simple_animal/hostile/blob/blobspore/proc/Zombify(mob/living/carbon/human/H)
|
||||
is_zombie = 1
|
||||
@@ -233,39 +234,40 @@
|
||||
return FALSE
|
||||
return ..()
|
||||
|
||||
/mob/living/simple_animal/hostile/blob/blobbernaut/Life()
|
||||
if(..())
|
||||
var/list/blobs_in_area = range(2, src)
|
||||
if(independent)
|
||||
return // strong independent blobbernaut that don't need no blob
|
||||
var/damagesources = 0
|
||||
if(!(locate(/obj/structure/blob) in blobs_in_area))
|
||||
damagesources++
|
||||
if(!factory)
|
||||
damagesources++
|
||||
else
|
||||
if(locate(/obj/structure/blob/core) in blobs_in_area)
|
||||
adjustHealth(-maxHealth*0.1)
|
||||
var/obj/effect/temp_visual/heal/H = new /obj/effect/temp_visual/heal(get_turf(src)) //hello yes you are being healed
|
||||
if(overmind)
|
||||
H.color = overmind.blobstrain.complementary_color
|
||||
else
|
||||
H.color = "#000000"
|
||||
if(locate(/obj/structure/blob/node) in blobs_in_area)
|
||||
adjustHealth(-maxHealth*0.05)
|
||||
var/obj/effect/temp_visual/heal/H = new /obj/effect/temp_visual/heal(get_turf(src))
|
||||
if(overmind)
|
||||
H.color = overmind.blobstrain.complementary_color
|
||||
else
|
||||
H.color = "#000000"
|
||||
if(damagesources)
|
||||
for(var/i in 1 to damagesources)
|
||||
adjustHealth(maxHealth*0.025) //take 2.5% of max health as damage when not near the blob or if the naut has no factory, 5% if both
|
||||
var/image/I = new('icons/mob/blob.dmi', src, "nautdamage", MOB_LAYER+0.01)
|
||||
I.appearance_flags = RESET_COLOR
|
||||
/mob/living/simple_animal/hostile/blob/blobbernaut/BiologicalLife(seconds, times_fired)
|
||||
if(!(. = ..()))
|
||||
return
|
||||
var/list/blobs_in_area = range(2, src)
|
||||
if(independent)
|
||||
return // strong independent blobbernaut that don't need no blob
|
||||
var/damagesources = 0
|
||||
if(!(locate(/obj/structure/blob) in blobs_in_area))
|
||||
damagesources++
|
||||
if(!factory)
|
||||
damagesources++
|
||||
else
|
||||
if(locate(/obj/structure/blob/core) in blobs_in_area)
|
||||
adjustHealth(-maxHealth*0.1)
|
||||
var/obj/effect/temp_visual/heal/H = new /obj/effect/temp_visual/heal(get_turf(src)) //hello yes you are being healed
|
||||
if(overmind)
|
||||
I.color = overmind.blobstrain.complementary_color
|
||||
flick_overlay_view(I, src, 8)
|
||||
H.color = overmind.blobstrain.complementary_color
|
||||
else
|
||||
H.color = "#000000"
|
||||
if(locate(/obj/structure/blob/node) in blobs_in_area)
|
||||
adjustHealth(-maxHealth*0.05)
|
||||
var/obj/effect/temp_visual/heal/H = new /obj/effect/temp_visual/heal(get_turf(src))
|
||||
if(overmind)
|
||||
H.color = overmind.blobstrain.complementary_color
|
||||
else
|
||||
H.color = "#000000"
|
||||
if(damagesources)
|
||||
for(var/i in 1 to damagesources)
|
||||
adjustHealth(maxHealth*0.025) //take 2.5% of max health as damage when not near the blob or if the naut has no factory, 5% if both
|
||||
var/image/I = new('icons/mob/blob.dmi', src, "nautdamage", MOB_LAYER+0.01)
|
||||
I.appearance_flags = RESET_COLOR
|
||||
if(overmind)
|
||||
I.color = overmind.blobstrain.complementary_color
|
||||
flick_overlay_view(I, src, 8)
|
||||
|
||||
/mob/living/simple_animal/hostile/blob/blobbernaut/adjustHealth(amount, updating_health = TRUE, forced = FALSE)
|
||||
. = ..()
|
||||
|
||||
@@ -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
|
||||
|
||||
|
||||
@@ -31,10 +31,6 @@
|
||||
beating = 0
|
||||
var/fakingit = 0
|
||||
|
||||
/obj/item/organ/heart/vampheart/prepare_eat()
|
||||
..()
|
||||
// Do cool stuff for eating vamp heart?
|
||||
|
||||
/obj/item/organ/heart/vampheart/Restart()
|
||||
beating = 0 // DONT run ..(). We don't want to start beating again.
|
||||
return 0
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -129,10 +129,10 @@
|
||||
target.Stun(power_time)
|
||||
to_chat(L, "<span class='notice'>[target] is fixed in place by your hypnotic gaze.</span>")
|
||||
target.next_move = world.time + power_time // <--- Use direct change instead. We want an unmodified delay to their next move // target.changeNext_move(power_time) // check click.dm
|
||||
target.notransform = TRUE // <--- Fuck it. We tried using next_move, but they could STILL resist. We're just doing a hard freeze.
|
||||
target.mob_transforming = TRUE // <--- Fuck it. We tried using next_move, but they could STILL resist. We're just doing a hard freeze.
|
||||
spawn(power_time)
|
||||
if(istype(target) && success)
|
||||
target.notransform = FALSE
|
||||
target.mob_transforming = FALSE
|
||||
if(istype(L) && target.stat == CONSCIOUS && (target in L.fov_view(10))) // They Woke Up! (Notice if within view)
|
||||
to_chat(L, "<span class='warning'>[target] has snapped out of their trance.</span>")
|
||||
|
||||
|
||||
@@ -20,7 +20,7 @@
|
||||
. = ..()
|
||||
if(!.)
|
||||
return
|
||||
if(owner.notransform || !get_turf(owner))
|
||||
if(owner.mob_transforming || !get_turf(owner))
|
||||
return FALSE
|
||||
|
||||
return TRUE
|
||||
@@ -83,7 +83,7 @@
|
||||
// Freeze Me
|
||||
user.next_move = world.time + mist_delay
|
||||
user.Stun(mist_delay, ignore_canstun = TRUE)
|
||||
user.notransform = TRUE
|
||||
user.mob_transforming = TRUE
|
||||
user.density = FALSE
|
||||
var/invis_was = user.invisibility
|
||||
user.invisibility = INVISIBILITY_MAXIMUM
|
||||
@@ -106,7 +106,7 @@
|
||||
user.dir = get_dir(my_turf, target_turf)
|
||||
user.next_move = world.time + mist_delay / 2
|
||||
user.Stun(mist_delay / 2, ignore_canstun = TRUE)
|
||||
user.notransform = FALSE
|
||||
user.mob_transforming = FALSE
|
||||
user.density = 1
|
||||
user.invisibility = invis_was
|
||||
|
||||
|
||||
@@ -101,7 +101,7 @@
|
||||
H.update_hair()
|
||||
H.update_body_parts()
|
||||
|
||||
// Wait here til we deactivate power or go unconscious
|
||||
// Wait here until we deactivate power or go unconscious
|
||||
var/datum/antagonist/bloodsucker/bloodsuckerdatum = owner.mind.has_antag_datum(ANTAG_DATUM_BLOODSUCKER)
|
||||
while (ContinueActive(owner) && istype(bloodsuckerdatum))//active && owner && owner.stat == CONSCIOUS)
|
||||
bloodsuckerdatum.AddBloodVolume(-0.2)
|
||||
|
||||
@@ -397,20 +397,31 @@
|
||||
escape_objective_possible = FALSE
|
||||
break
|
||||
var/changeling_objective = rand(1,3)
|
||||
var/generic_absorb_objective = FALSE
|
||||
var/multiple_lings = length(get_antag_minds(/datum/antagonist/changeling,TRUE)) > 1
|
||||
switch(changeling_objective)
|
||||
if(1)
|
||||
var/datum/objective/absorb/absorb_objective = new
|
||||
absorb_objective.owner = owner
|
||||
absorb_objective.gen_amount_goal(6, 8)
|
||||
objectives += absorb_objective
|
||||
generic_absorb_objective = TRUE
|
||||
if(2)
|
||||
var/datum/objective/absorb_changeling/ac = new
|
||||
ac.owner = owner
|
||||
objectives += ac
|
||||
if(multiple_lings)
|
||||
var/datum/objective/absorb_changeling/ac = new
|
||||
ac.owner = owner
|
||||
objectives += ac
|
||||
else
|
||||
generic_absorb_objective = TRUE
|
||||
if(3)
|
||||
var/datum/objective/absorb_most/ac = new
|
||||
ac.owner = owner
|
||||
objectives += ac
|
||||
if(multiple_lings)
|
||||
var/datum/objective/absorb_most/ac = new
|
||||
ac.owner = owner
|
||||
objectives += ac
|
||||
else
|
||||
generic_absorb_objective = TRUE
|
||||
|
||||
if(generic_absorb_objective)
|
||||
var/datum/objective/absorb/absorb_objective = new
|
||||
absorb_objective.owner = owner
|
||||
absorb_objective.gen_amount_goal(6, 8)
|
||||
objectives += absorb_objective
|
||||
|
||||
if(prob(60))
|
||||
if(prob(85))
|
||||
|
||||
@@ -21,7 +21,7 @@
|
||||
var/datum/changelingprofile/chosen_prof = changeling.get_dna(chosen_name)
|
||||
if(!chosen_prof)
|
||||
return
|
||||
if(!user || user.notransform)
|
||||
if(!user || user.mob_transforming)
|
||||
return 0
|
||||
to_chat(user, "<span class='notice'>We transform our appearance.</span>")
|
||||
|
||||
|
||||
@@ -11,9 +11,9 @@
|
||||
|
||||
//Transform into a monkey.
|
||||
/obj/effect/proc_holder/changeling/lesserform/sting_action(mob/living/carbon/human/user)
|
||||
if(!user || user.notransform)
|
||||
if(!user || user.mob_transforming)
|
||||
return 0
|
||||
to_chat(user, "<span class='warning'>Our genes cry out!</span>")
|
||||
|
||||
user.monkeyize(TR_KEEPITEMS | TR_KEEPIMPLANTS | TR_KEEPORGANS | TR_KEEPDAMAGE | TR_KEEPVIRUS | TR_KEEPSE)
|
||||
return TRUE
|
||||
return TRUE
|
||||
|
||||
@@ -432,15 +432,18 @@
|
||||
/obj/item/shield/changeling
|
||||
name = "shield-like mass"
|
||||
desc = "A mass of tough, boney tissue. You can still see the fingers as a twisted pattern in the shield."
|
||||
item_flags = ABSTRACT | DROPDEL
|
||||
item_flags = ABSTRACT | DROPDEL | ITEM_CAN_BLOCK
|
||||
icon = 'icons/obj/items_and_weapons.dmi'
|
||||
icon_state = "ling_shield"
|
||||
lefthand_file = 'icons/mob/inhands/antag/changeling_lefthand.dmi'
|
||||
righthand_file = 'icons/mob/inhands/antag/changeling_righthand.dmi'
|
||||
block_chance = 50
|
||||
block_parry_data = /datum/block_parry_data/shield/changeling
|
||||
|
||||
var/remaining_uses //Set by the changeling ability.
|
||||
|
||||
/datum/block_parry_data/shield/changeling
|
||||
block_slowdown = 0
|
||||
|
||||
/obj/item/shield/changeling/Initialize(mapload)
|
||||
. = ..()
|
||||
ADD_TRAIT(src, TRAIT_NODROP, CHANGELING_TRAIT)
|
||||
@@ -451,7 +454,7 @@
|
||||
block_return[BLOCK_RETURN_BLOCK_CAPACITY] = (block_return[BLOCK_RETURN_BLOCK_CAPACITY] || 0) + remaining_uses
|
||||
return ..()
|
||||
|
||||
/obj/item/shield/changeling/run_block(mob/living/owner, atom/object, damage, attack_text, attack_type, armour_penetration, mob/attacker, def_zone, final_block_chance, list/block_return)
|
||||
/obj/item/shield/changeling/active_block(mob/living/owner, atom/object, damage, attack_text, attack_type, armour_penetration, mob/attacker, def_zone, final_block_chance, list/block_return)
|
||||
. = ..()
|
||||
if(--remaining_uses < 1)
|
||||
if(ishuman(loc))
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
/obj/effect/proc_holder/changeling/spiders
|
||||
name = "Spread Infestation"
|
||||
desc = "Our form divides, creating arachnids which will grow into deadly beasts."
|
||||
helptext = "The spiders are thoughtless creatures, and may attack their creators when fully grown. Requires at least 3 DNA gained through Absorb, and not through DNA sting. This ability is very loud, and will guarantee that our blood will react violently to heat."
|
||||
helptext = "The spiders are thoughtless creatures, and may attack their creators when fully grown. Requires at least 3 DNA gained through Absorb (regardless of current amount), and not through DNA sting. This ability is very loud, and will guarantee that our blood will react violently to heat."
|
||||
chemical_cost = 45
|
||||
dna_cost = 1
|
||||
loudness = 4
|
||||
|
||||
@@ -40,8 +40,9 @@
|
||||
if(!shield_health)
|
||||
return "<span class='warning'>Its shield has been destroyed!</span>"
|
||||
|
||||
/mob/living/simple_animal/hostile/clockwork/marauder/Life()
|
||||
..()
|
||||
/mob/living/simple_animal/hostile/clockwork/marauder/BiologicalLife(seconds, times_fired)
|
||||
if(!(. = ..()))
|
||||
return
|
||||
var/turf/T = get_turf(src)
|
||||
var/turf/open/space/S = isspaceturf(T)? T : null
|
||||
var/less_space_damage
|
||||
|
||||
@@ -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 ..()
|
||||
|
||||
@@ -801,7 +801,7 @@
|
||||
var/turf/T = get_turf(user)
|
||||
qdel(src)
|
||||
var/datum/action/innate/cult/spear/S = new(user)
|
||||
var/obj/item/twohanded/cult_spear/rite = new(T)
|
||||
var/obj/item/cult_spear/rite = new(T)
|
||||
S.Grant(user, rite)
|
||||
rite.spear_act = S
|
||||
if(user.put_in_hands(rite))
|
||||
|
||||
@@ -100,7 +100,7 @@
|
||||
user.apply_damage(30, BRUTE, pick(BODY_ZONE_L_ARM, BODY_ZONE_R_ARM))
|
||||
user.dropItemToGround(src)
|
||||
|
||||
/obj/item/twohanded/required/cult_bastard
|
||||
/obj/item/cult_bastard
|
||||
name = "bloody bastard sword"
|
||||
desc = "An enormous sword used by Nar'Sien cultists to rapidly harvest the souls of non-believers."
|
||||
w_class = WEIGHT_CLASS_HUGE
|
||||
@@ -127,31 +127,35 @@
|
||||
var/spin_cooldown = 250
|
||||
var/dash_toggled = TRUE
|
||||
|
||||
/obj/item/twohanded/required/cult_bastard/Initialize()
|
||||
/obj/item/cult_bastard/Initialize()
|
||||
. = ..()
|
||||
set_light(4)
|
||||
jaunt = new(src)
|
||||
linked_action = new(src)
|
||||
AddComponent(/datum/component/butchering, 50, 80)
|
||||
|
||||
/obj/item/twohanded/required/cult_bastard/examine(mob/user)
|
||||
/obj/item/cult_bastard/ComponentInitialize()
|
||||
. = ..()
|
||||
AddComponent(/datum/component/butchering, 50, 80)
|
||||
AddComponent(/datum/component/two_handed, require_twohands=TRUE)
|
||||
|
||||
/obj/item/cult_bastard/examine(mob/user)
|
||||
. = ..()
|
||||
if(contents.len)
|
||||
. += "<br><b>There are [contents.len] souls trapped within the sword's core.</b>"
|
||||
else
|
||||
. += "<br>The sword appears to be quite lifeless."
|
||||
|
||||
/obj/item/twohanded/required/cult_bastard/can_be_pulled(user)
|
||||
/obj/item/cult_bastard/can_be_pulled(user)
|
||||
return FALSE
|
||||
|
||||
/obj/item/twohanded/required/cult_bastard/attack_self(mob/user)
|
||||
/obj/item/cult_bastard/attack_self(mob/user)
|
||||
dash_toggled = !dash_toggled
|
||||
if(dash_toggled)
|
||||
to_chat(loc, "<span class='notice'>You raise [src] and prepare to jaunt with it.</span>")
|
||||
else
|
||||
to_chat(loc, "<span class='notice'>You lower [src] and prepare to swing it normally.</span>")
|
||||
|
||||
/obj/item/twohanded/required/cult_bastard/pickup(mob/living/user)
|
||||
/obj/item/cult_bastard/pickup(mob/living/user)
|
||||
. = ..()
|
||||
if(!iscultist(user))
|
||||
if(!is_servant_of_ratvar(user))
|
||||
@@ -171,13 +175,13 @@
|
||||
linked_action.Grant(user, src)
|
||||
user.update_icons()
|
||||
|
||||
/obj/item/twohanded/required/cult_bastard/dropped(mob/user)
|
||||
/obj/item/cult_bastard/dropped(mob/user)
|
||||
. = ..()
|
||||
linked_action.Remove(user)
|
||||
jaunt.Remove(user)
|
||||
user.update_icons()
|
||||
|
||||
/obj/item/twohanded/required/cult_bastard/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/cult_bastard/run_block(mob/living/owner, atom/object, damage, attack_text, attack_type, armour_penetration, mob/attacker, def_zone, final_block_chance, list/block_return)
|
||||
if(spinning && is_energy_reflectable_projectile(object) && (attack_type & ATTACK_TYPE_PROJECTILE))
|
||||
playsound(src, pick('sound/weapons/effects/ric1.ogg', 'sound/weapons/effects/ric2.ogg', 'sound/weapons/effects/ric3.ogg', 'sound/weapons/effects/ric4.ogg', 'sound/weapons/effects/ric5.ogg'), 100, 1)
|
||||
return BLOCK_SUCCESS | BLOCK_PHYSICAL_EXTERNAL | BLOCK_REDIRECTED | BLOCK_SHOULD_REDIRECT
|
||||
@@ -192,7 +196,7 @@
|
||||
return BLOCK_SUCCESS | BLOCK_PHYSICAL_EXTERNAL
|
||||
return BLOCK_NONE
|
||||
|
||||
/obj/item/twohanded/required/cult_bastard/afterattack(atom/target, mob/user, proximity, click_parameters)
|
||||
/obj/item/cult_bastard/afterattack(atom/target, mob/user, proximity, click_parameters)
|
||||
. = ..()
|
||||
if(dash_toggled && !proximity)
|
||||
jaunt.Teleport(user, target)
|
||||
@@ -235,7 +239,7 @@
|
||||
button_icon_state = "sintouch"
|
||||
var/cooldown = 0
|
||||
var/mob/living/carbon/human/holder
|
||||
var/obj/item/twohanded/required/cult_bastard/sword
|
||||
var/obj/item/cult_bastard/sword
|
||||
|
||||
/datum/action/innate/cult/spin2win/Grant(mob/user, obj/bastard)
|
||||
. = ..()
|
||||
@@ -273,6 +277,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)
|
||||
@@ -686,7 +691,7 @@
|
||||
to_chat(user, "<span class='warning'>\The [src] can only transport items!</span>")
|
||||
|
||||
|
||||
/obj/item/twohanded/cult_spear
|
||||
/obj/item/cult_spear
|
||||
name = "blood halberd"
|
||||
desc = "A sickening spear composed entirely of crystallized blood."
|
||||
icon_state = "bloodspear0"
|
||||
@@ -694,8 +699,6 @@
|
||||
righthand_file = 'icons/mob/inhands/weapons/polearms_righthand.dmi'
|
||||
slot_flags = 0
|
||||
force = 17
|
||||
force_unwielded = 17
|
||||
force_wielded = 24
|
||||
throwforce = 40
|
||||
throw_speed = 2
|
||||
armour_penetration = 30
|
||||
@@ -704,20 +707,36 @@
|
||||
sharpness = IS_SHARP
|
||||
hitsound = 'sound/weapons/bladeslice.ogg'
|
||||
var/datum/action/innate/cult/spear/spear_act
|
||||
var/wielded = FALSE // track wielded status on item
|
||||
|
||||
/obj/item/twohanded/cult_spear/Initialize()
|
||||
|
||||
/obj/item/cult_spear/Initialize()
|
||||
. = ..()
|
||||
RegisterSignal(src, COMSIG_TWOHANDED_WIELD, .proc/on_wield)
|
||||
RegisterSignal(src, COMSIG_TWOHANDED_UNWIELD, .proc/on_unwield)
|
||||
|
||||
/obj/item/cult_spear/ComponentInitialize()
|
||||
. = ..()
|
||||
AddComponent(/datum/component/butchering, 100, 90)
|
||||
AddComponent(/datum/component/two_handed, force_unwielded=17, force_wielded=24, icon_wielded="bloodspear1")
|
||||
|
||||
/obj/item/twohanded/cult_spear/Destroy()
|
||||
/// triggered on wield of two handed item
|
||||
/obj/item/cult_spear/proc/on_wield(obj/item/source, mob/user)
|
||||
wielded = TRUE
|
||||
|
||||
/// triggered on unwield of two handed item
|
||||
/obj/item/cult_spear/proc/on_unwield(obj/item/source, mob/user)
|
||||
wielded = FALSE
|
||||
|
||||
/obj/item/cult_spear/update_icon_state()
|
||||
icon_state = "bloodspear0"
|
||||
|
||||
/obj/item/cult_spear/Destroy()
|
||||
if(spear_act)
|
||||
qdel(spear_act)
|
||||
..()
|
||||
|
||||
/obj/item/twohanded/cult_spear/update_icon_state()
|
||||
icon_state = "bloodspear[wielded]"
|
||||
|
||||
/obj/item/twohanded/cult_spear/throw_impact(atom/hit_atom, datum/thrownthing/throwingdatum)
|
||||
/obj/item/cult_spear/throw_impact(atom/hit_atom, datum/thrownthing/throwingdatum)
|
||||
var/turf/T = get_turf(hit_atom)
|
||||
if(isliving(hit_atom))
|
||||
var/mob/living/L = hit_atom
|
||||
@@ -740,7 +759,7 @@
|
||||
else
|
||||
..()
|
||||
|
||||
/obj/item/twohanded/cult_spear/proc/break_spear(turf/T)
|
||||
/obj/item/cult_spear/proc/break_spear(turf/T)
|
||||
if(src)
|
||||
if(!T)
|
||||
T = get_turf(src)
|
||||
@@ -751,7 +770,7 @@
|
||||
playsound(T, 'sound/effects/glassbr3.ogg', 100)
|
||||
qdel(src)
|
||||
|
||||
/obj/item/twohanded/cult_spear/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/cult_spear/run_block(mob/living/owner, atom/object, damage, attack_text, attack_type, armour_penetration, mob/attacker, def_zone, final_block_chance, list/block_return)
|
||||
if(wielded)
|
||||
final_block_chance *= 2
|
||||
if(prob(final_block_chance))
|
||||
@@ -770,7 +789,7 @@
|
||||
desc = "Call the blood spear back to your hand!"
|
||||
background_icon_state = "bg_demon"
|
||||
button_icon_state = "bloodspear"
|
||||
var/obj/item/twohanded/cult_spear/spear
|
||||
var/obj/item/cult_spear/spear
|
||||
var/cooldown = 0
|
||||
|
||||
/datum/action/innate/cult/spear/Grant(mob/user, obj/blood_spear)
|
||||
|
||||
@@ -48,8 +48,9 @@
|
||||
..()
|
||||
boost = world.time + 30
|
||||
|
||||
/mob/living/simple_animal/imp/Life()
|
||||
..()
|
||||
/mob/living/simple_animal/imp/BiologicalLife(seconds, times_fired)
|
||||
if(!(. = ..()))
|
||||
return
|
||||
if(boost<world.time)
|
||||
speed = 1
|
||||
else
|
||||
|
||||
@@ -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>")
|
||||
@@ -107,7 +107,8 @@
|
||||
mind.add_antag_datum(/datum/antagonist/revenant)
|
||||
|
||||
//Life, Stat, Hud Updates, and Say
|
||||
/mob/living/simple_animal/revenant/Life()
|
||||
/mob/living/simple_animal/revenant/BiologicalLife(seconds, times_fired)
|
||||
. = ..()
|
||||
if(stasis)
|
||||
return
|
||||
if(revealed && essence <= 0)
|
||||
@@ -120,14 +121,13 @@
|
||||
to_chat(src, "<span class='revenboldnotice'>You are once more concealed.</span>")
|
||||
if(unstun_time && world.time >= unstun_time)
|
||||
unstun_time = 0
|
||||
notransform = FALSE
|
||||
mob_transforming = FALSE
|
||||
to_chat(src, "<span class='revenboldnotice'>You can move again!</span>")
|
||||
if(essence_regenerating && !inhibited && essence < essence_regen_cap) //While inhibited, essence will not regenerate
|
||||
essence = min(essence_regen_cap, essence+essence_regen_amount)
|
||||
update_action_buttons_icon() //because we update something required by our spells in life, we need to update our buttons
|
||||
update_spooky_icon()
|
||||
update_health_hud()
|
||||
..()
|
||||
|
||||
/mob/living/simple_animal/revenant/Stat()
|
||||
..()
|
||||
@@ -218,7 +218,7 @@
|
||||
return 0
|
||||
stasis = TRUE
|
||||
to_chat(src, "<span class='revendanger'>NO! No... it's too late, you can feel your essence [pick("breaking apart", "drifting away")]...</span>")
|
||||
notransform = TRUE
|
||||
mob_transforming = TRUE
|
||||
revealed = TRUE
|
||||
invisibility = 0
|
||||
playsound(src, 'sound/effects/screech.ogg', 100, 1)
|
||||
@@ -260,7 +260,7 @@
|
||||
return
|
||||
if(time <= 0)
|
||||
return
|
||||
notransform = TRUE
|
||||
mob_transforming = TRUE
|
||||
if(!unstun_time)
|
||||
to_chat(src, "<span class='revendanger'>You cannot move!</span>")
|
||||
unstun_time = world.time + time
|
||||
@@ -271,7 +271,7 @@
|
||||
|
||||
/mob/living/simple_animal/revenant/proc/update_spooky_icon()
|
||||
if(revealed)
|
||||
if(notransform)
|
||||
if(mob_transforming)
|
||||
if(draining)
|
||||
icon_state = icon_drain
|
||||
else
|
||||
@@ -320,7 +320,7 @@
|
||||
/mob/living/simple_animal/revenant/proc/death_reset()
|
||||
revealed = FALSE
|
||||
unreveal_time = 0
|
||||
notransform = 0
|
||||
mob_transforming = 0
|
||||
unstun_time = 0
|
||||
inhibited = FALSE
|
||||
draining = FALSE
|
||||
|
||||
@@ -257,6 +257,8 @@ GLOBAL_LIST_INIT(blacklisted_malf_machines, typecacheof(list(
|
||||
return
|
||||
if (active)
|
||||
return //prevent the AI from activating an already active doomsday
|
||||
if (owner_AI.shunted)
|
||||
return //prevent AI from activating doomsday while shunted.
|
||||
active = TRUE
|
||||
set_us_up_the_bomb(owner)
|
||||
|
||||
|
||||
@@ -234,7 +234,7 @@
|
||||
H.equip_to_slot_or_del(new /obj/item/clothing/shoes/roman(H), SLOT_SHOES)
|
||||
H.put_in_hands(new /obj/item/shield/riot/roman(H), TRUE)
|
||||
H.put_in_hands(new /obj/item/claymore(H), TRUE)
|
||||
H.equip_to_slot_or_del(new /obj/item/twohanded/spear(H), SLOT_BACK)
|
||||
H.equip_to_slot_or_del(new /obj/item/spear(H), SLOT_BACK)
|
||||
|
||||
|
||||
/obj/item/voodoo
|
||||
@@ -369,7 +369,7 @@
|
||||
var/mob/living/carbon/last_user
|
||||
|
||||
/obj/item/warpwhistle/proc/interrupted(mob/living/carbon/user)
|
||||
if(!user || QDELETED(src) || user.notransform)
|
||||
if(!user || QDELETED(src) || user.mob_transforming)
|
||||
on_cooldown = FALSE
|
||||
return TRUE
|
||||
return FALSE
|
||||
|
||||
@@ -430,12 +430,12 @@
|
||||
/datum/spellbook_entry/item/mjolnir
|
||||
name = "Mjolnir"
|
||||
desc = "A mighty hammer on loan from Thor, God of Thunder. It crackles with barely contained power."
|
||||
item_path = /obj/item/twohanded/mjollnir
|
||||
item_path = /obj/item/mjollnir
|
||||
|
||||
/datum/spellbook_entry/item/singularity_hammer
|
||||
name = "Singularity Hammer"
|
||||
desc = "A hammer that creates an intensely powerful field of gravity where it strikes, pulling everything nearby to the point of impact."
|
||||
item_path = /obj/item/twohanded/singularityhammer
|
||||
item_path = /obj/item/singularityhammer
|
||||
|
||||
/datum/spellbook_entry/item/battlemage
|
||||
name = "Battlemage Armour"
|
||||
@@ -560,6 +560,27 @@
|
||||
. += "You cast it [times] times.<br>"
|
||||
return .
|
||||
|
||||
/datum/spellbook_entry/summon/curse_of_madness
|
||||
name = "Curse of Madness"
|
||||
desc = "Curses the station, warping the minds of everyone inside, causing lasting traumas. Warning: this spell can affect you if not cast from a safe distance."
|
||||
cost = 4
|
||||
|
||||
/datum/spellbook_entry/summon/curse_of_madness/Buy(mob/living/carbon/human/user, obj/item/spellbook/book)
|
||||
SSblackbox.record_feedback("tally", "wizard_spell_learned", 1, name)
|
||||
active = TRUE
|
||||
var/message = stripped_input(user, "Whisper a secret truth to drive your victims to madness.", "Whispers of Madness")
|
||||
if(!message)
|
||||
return FALSE
|
||||
curse_of_madness(user, message)
|
||||
to_chat(user, "<span class='notice'>You have cast the curse of insanity!</span>")
|
||||
playsound(user, 'sound/magic/mandswap.ogg', 50, 1)
|
||||
return TRUE
|
||||
|
||||
/datum/spellbook_entry/summon/curse_of_madness/IsAvailible()
|
||||
if(!SSticker.mode) // In case spellbook is placed on map
|
||||
return FALSE
|
||||
return (!CONFIG_GET(flag/no_summon_traumas) && ..())
|
||||
|
||||
/obj/item/spellbook
|
||||
name = "spell book"
|
||||
desc = "An unearthly tome that glows with power."
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
/obj/item/organ/genital
|
||||
color = "#fcccb3"
|
||||
w_class = WEIGHT_CLASS_SMALL
|
||||
organ_flags = ORGAN_NO_DISMEMBERMENT
|
||||
organ_flags = ORGAN_NO_DISMEMBERMENT|ORGAN_EDIBLE
|
||||
var/shape
|
||||
var/sensitivity = 1 // wow if this were ever used that'd be cool but it's not but i'm keeping it for my unshit code
|
||||
var/genital_flags //see citadel_defines.dm
|
||||
|
||||
@@ -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,51 @@
|
||||
|
||||
/// 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>
|
||||
@@ -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)
|
||||
|
||||
@@ -7,7 +7,7 @@
|
||||
#define AMMO_DROP_LIFETIME 300
|
||||
#define CTF_REQUIRED_PLAYERS 4
|
||||
|
||||
/obj/item/twohanded/ctf
|
||||
/obj/item/ctf
|
||||
name = "banner"
|
||||
icon = 'icons/obj/items_and_weapons.dmi'
|
||||
icon_state = "banner"
|
||||
@@ -16,6 +16,7 @@
|
||||
righthand_file = 'icons/mob/inhands/equipment/banners_righthand.dmi'
|
||||
desc = "A banner with Nanotrasen's logo on it."
|
||||
slowdown = 2
|
||||
item_flags = SLOWS_WHILE_IN_HAND
|
||||
throw_speed = 0
|
||||
throw_range = 1
|
||||
force = 200
|
||||
@@ -28,16 +29,20 @@
|
||||
var/obj/effect/ctf/flag_reset/reset
|
||||
var/reset_path = /obj/effect/ctf/flag_reset
|
||||
|
||||
/obj/item/twohanded/ctf/Destroy()
|
||||
/obj/item/ctf/Destroy()
|
||||
QDEL_NULL(reset)
|
||||
return ..()
|
||||
|
||||
/obj/item/twohanded/ctf/Initialize()
|
||||
/obj/item/ctf/Initialize()
|
||||
. = ..()
|
||||
if(!reset)
|
||||
reset = new reset_path(get_turf(src))
|
||||
|
||||
/obj/item/twohanded/ctf/process()
|
||||
/obj/item/ctf/ComponentInitialize()
|
||||
. = ..()
|
||||
AddComponent(/datum/component/two_handed)
|
||||
|
||||
/obj/item/ctf/process()
|
||||
if(is_ctf_target(loc)) //don't reset from someone's hands.
|
||||
return PROCESS_KILL
|
||||
if(world.time > reset_cooldown)
|
||||
@@ -49,7 +54,7 @@
|
||||
STOP_PROCESSING(SSobj, src)
|
||||
|
||||
//ATTACK HAND IGNORING PARENT RETURN VALUE
|
||||
/obj/item/twohanded/ctf/attack_hand(mob/living/user)
|
||||
/obj/item/ctf/attack_hand(mob/living/user)
|
||||
if(!is_ctf_target(user) && !anyonecanpickup)
|
||||
to_chat(user, "Non players shouldn't be moving the flag!")
|
||||
return
|
||||
@@ -73,7 +78,7 @@
|
||||
STOP_PROCESSING(SSobj, src)
|
||||
..()
|
||||
|
||||
/obj/item/twohanded/ctf/dropped(mob/user)
|
||||
/obj/item/ctf/dropped(mob/user)
|
||||
..()
|
||||
user.anchored = FALSE
|
||||
user.status_flags |= CANPUSH
|
||||
@@ -86,7 +91,7 @@
|
||||
anchored = TRUE
|
||||
|
||||
|
||||
/obj/item/twohanded/ctf/red
|
||||
/obj/item/ctf/red
|
||||
name = "red flag"
|
||||
icon_state = "banner-red"
|
||||
item_state = "banner-red"
|
||||
@@ -95,7 +100,7 @@
|
||||
reset_path = /obj/effect/ctf/flag_reset/red
|
||||
|
||||
|
||||
/obj/item/twohanded/ctf/blue
|
||||
/obj/item/ctf/blue
|
||||
name = "blue flag"
|
||||
icon_state = "banner-blue"
|
||||
item_state = "banner-blue"
|
||||
@@ -276,8 +281,8 @@
|
||||
attack_ghost(ghost)
|
||||
|
||||
/obj/machinery/capture_the_flag/attackby(obj/item/I, mob/user, params)
|
||||
if(istype(I, /obj/item/twohanded/ctf))
|
||||
var/obj/item/twohanded/ctf/flag = I
|
||||
if(istype(I, /obj/item/ctf))
|
||||
var/obj/item/ctf/flag = I
|
||||
if(flag.team != src.team)
|
||||
user.transferItemToLoc(flag, get_turf(flag.reset), TRUE)
|
||||
points++
|
||||
@@ -294,7 +299,7 @@
|
||||
if(istype(mob_area, /area/ctf))
|
||||
to_chat(M, "<span class='narsie [team_span]'>[team] team wins!</span>")
|
||||
to_chat(M, "<span class='userdanger'>Teams have been cleared. Click on the machines to vote to begin another round.</span>")
|
||||
for(var/obj/item/twohanded/ctf/W in M)
|
||||
for(var/obj/item/ctf/W in M)
|
||||
M.dropItemToGround(W)
|
||||
M.dust()
|
||||
for(var/obj/machinery/control_point/control in GLOB.machines)
|
||||
@@ -335,7 +340,7 @@
|
||||
var/list/ctf_object_typecache = typecacheof(list(
|
||||
/obj/machinery,
|
||||
/obj/effect/ctf,
|
||||
/obj/item/twohanded/ctf
|
||||
/obj/item/ctf
|
||||
))
|
||||
for(var/atm in A)
|
||||
if (isturf(A) || ismob(A) || isarea(A))
|
||||
|
||||
@@ -661,5 +661,5 @@
|
||||
|
||||
/datum/outfit/lavaknight/captain
|
||||
name ="Cydonian Knight Captain"
|
||||
l_pocket = /obj/item/twohanded/dualsaber/hypereutactic
|
||||
l_pocket = /obj/item/dualsaber/hypereutactic
|
||||
id = /obj/item/card/id/knight/captain
|
||||
|
||||
@@ -189,6 +189,8 @@
|
||||
if(!ishuman(user) || !user.mind || (user.mind in SSticker.mode.wizards))
|
||||
to_chat(user, "<span class='warning'>You feel the magic of the dice is restricted to ordinary humans! You should leave it alone.</span>")
|
||||
user.dropItemToGround(src)
|
||||
return
|
||||
return ..()
|
||||
|
||||
|
||||
/obj/item/dice/d20/fate/proc/effect(var/mob/living/carbon/human/user,roll)
|
||||
|
||||
@@ -1,20 +1,39 @@
|
||||
|
||||
/*Cabin areas*/
|
||||
/area/awaymission/snowforest
|
||||
name = "Snow Forest"
|
||||
icon_state = "away"
|
||||
requires_power = FALSE
|
||||
dynamic_lighting = DYNAMIC_LIGHTING_ENABLED
|
||||
|
||||
/area/awaymission/cabin
|
||||
name = "Cabin"
|
||||
icon_state = "away2"
|
||||
requires_power = TRUE
|
||||
dynamic_lighting = DYNAMIC_LIGHTING_ENABLED
|
||||
|
||||
/area/awaymission/snowforest/lumbermill
|
||||
/area/awaymission/cabin/snowforest
|
||||
name = "Snow Forest"
|
||||
icon_state = "away"
|
||||
dynamic_lighting = DYNAMIC_LIGHTING_DISABLED
|
||||
|
||||
/area/awaymission/cabin/snowforest/sovietsurface
|
||||
name = "Snow Forest"
|
||||
icon_state = "awaycontent29"
|
||||
requires_power = FALSE
|
||||
|
||||
/area/awaymission/cabin/lumbermill
|
||||
name = "Lumbermill"
|
||||
icon_state = "away3"
|
||||
requires_power = FALSE
|
||||
dynamic_lighting = DYNAMIC_LIGHTING_DISABLED
|
||||
|
||||
/area/awaymission/cabin/caves/sovietcave
|
||||
name = "Soviet Bunker"
|
||||
icon_state = "awaycontent4"
|
||||
|
||||
/area/awaymission/cabin/caves
|
||||
name = "North Snowdin Caves"
|
||||
icon_state = "awaycontent15"
|
||||
dynamic_lighting = DYNAMIC_LIGHTING_FORCED
|
||||
|
||||
/area/awaymission/cabin/caves/mountain
|
||||
name = "North Snowdin Mountains"
|
||||
icon_state = "awaycontent24"
|
||||
|
||||
/obj/structure/firepit
|
||||
name = "firepit"
|
||||
@@ -92,7 +111,7 @@
|
||||
egg_type = null
|
||||
speak = list()
|
||||
|
||||
/*Cabin's forest*/
|
||||
/*Cabin's forest. Removed in the new cabin map since it was buggy and I prefer manual placement.*/
|
||||
/datum/mapGenerator/snowy
|
||||
modules = list(/datum/mapGeneratorModule/bottomlayer/snow, \
|
||||
/datum/mapGeneratorModule/snow/pineTrees, \
|
||||
@@ -136,4 +155,4 @@
|
||||
endTurfX = 159
|
||||
endTurfY = 157
|
||||
startTurfX = 37
|
||||
startTurfY = 35
|
||||
startTurfY = 35
|
||||
@@ -475,43 +475,26 @@
|
||||
|
||||
/obj/effect/spawner/lootdrop/snowdin/dungeonlite
|
||||
name = "dungeon lite"
|
||||
loot = list(/obj/item/melee/classic_baton = 11,
|
||||
/obj/item/melee/classic_baton/telescopic = 12,
|
||||
/obj/item/book/granter/spell/smoke = 10,
|
||||
loot = list(/obj/item/book/granter/spell/smoke = 10,
|
||||
/obj/item/book/granter/spell/blind = 10,
|
||||
/obj/item/storage/firstaid/regular = 45,
|
||||
/obj/item/storage/firstaid/toxin = 35,
|
||||
/obj/item/storage/firstaid/brute = 27,
|
||||
/obj/item/storage/firstaid/fire = 27,
|
||||
/obj/item/storage/toolbox/syndicate = 12,
|
||||
/obj/item/grenade/plastic/c4 = 7,
|
||||
/obj/item/grenade/clusterbuster/smoke = 15,
|
||||
/obj/item/clothing/under/chameleon = 13,
|
||||
/obj/item/clothing/shoes/chameleon/noslip = 10,
|
||||
/obj/item/borg/upgrade/ddrill = 3)
|
||||
|
||||
/obj/effect/spawner/lootdrop/snowdin/dungeonmid
|
||||
name = "dungeon mid"
|
||||
loot = list(/obj/item/defibrillator/compact = 6,
|
||||
/obj/item/storage/firstaid/tactical = 35,
|
||||
/obj/item/shield/energy = 6,
|
||||
/obj/item/shield/riot/tele = 12,
|
||||
/obj/item/dnainjector/lasereyesmut = 7,
|
||||
/obj/item/gun/magic/wand/fireball/inert = 3,
|
||||
loot = list(/obj/item/shield/riot = 12,
|
||||
/obj/item/pneumatic_cannon = 15,
|
||||
/obj/item/melee/transforming/energy/sword = 7,
|
||||
/obj/item/book/granter/spell/knock = 15,
|
||||
/obj/item/book/granter/spell/summonitem = 20,
|
||||
/obj/item/book/granter/spell/forcewall = 17,
|
||||
/obj/item/storage/backpack/holding = 12,
|
||||
/obj/item/grenade/spawnergrenade/manhacks = 6,
|
||||
/obj/item/grenade/spawnergrenade/spesscarp = 7,
|
||||
/obj/item/grenade/clusterbuster/inferno = 3,
|
||||
/obj/item/stack/sheet/mineral/diamond{amount = 15} = 10,
|
||||
/obj/item/stack/sheet/mineral/uranium{amount = 15} = 10,
|
||||
/obj/item/stack/sheet/mineral/plasma{amount = 15} = 10,
|
||||
/obj/item/stack/sheet/mineral/gold{amount = 15} = 10,
|
||||
/obj/item/book/granter/spell/barnyard = 4,
|
||||
/obj/item/pickaxe/drill/diamonddrill = 6,
|
||||
/obj/item/borg/upgrade/vtec = 7,
|
||||
/obj/item/borg/upgrade/disablercooler = 7)
|
||||
@@ -519,21 +502,12 @@
|
||||
|
||||
/obj/effect/spawner/lootdrop/snowdin/dungeonheavy
|
||||
name = "dungeon heavy"
|
||||
loot = list(/obj/item/twohanded/singularityhammer = 25,
|
||||
/obj/item/twohanded/mjollnir = 10,
|
||||
/obj/item/twohanded/fireaxe = 25,
|
||||
loot = list(/obj/item/fireaxe = 25,
|
||||
/obj/item/organ/brain/alien = 17,
|
||||
/obj/item/twohanded/dualsaber = 15,
|
||||
/obj/item/organ/heart/demon = 7,
|
||||
/obj/item/gun/ballistic/automatic/c20r/unrestricted = 16,
|
||||
/obj/item/gun/magic/wand/resurrection/inert = 15,
|
||||
/obj/item/gun/magic/wand/resurrection = 10,
|
||||
/obj/item/uplink/old = 2,
|
||||
/obj/item/book/granter/spell/charge = 12,
|
||||
/obj/item/grenade/clusterbuster/spawner_manhacks = 15,
|
||||
/obj/item/book/granter/spell/fireball = 10,
|
||||
/obj/item/organ/heart/cursed = 7,
|
||||
/obj/item/book/granter/spell/forcewall = 17,
|
||||
/obj/item/gun/magic/wand/fireball/inert = 3,
|
||||
/obj/item/pickaxe/drill/jackhammer = 30,
|
||||
/obj/item/borg/upgrade/syndicate = 13,
|
||||
/obj/item/borg/upgrade/selfrepair = 17)
|
||||
|
||||
/obj/effect/spawner/lootdrop/snowdin/dungeonmisc
|
||||
@@ -544,7 +518,7 @@
|
||||
loot = list(/obj/item/stack/sheet/mineral/snow{amount = 25} = 10,
|
||||
/obj/item/toy/snowball = 15,
|
||||
/obj/item/shovel = 10,
|
||||
/obj/item/twohanded/spear = 8,
|
||||
/obj/item/spear = 8,
|
||||
)
|
||||
|
||||
//special items//--
|
||||
|
||||
@@ -1,51 +0,0 @@
|
||||
//Spacebattle Areas
|
||||
|
||||
/area/awaymission/spacebattle
|
||||
name = "Space Battle"
|
||||
icon_state = "awaycontent1"
|
||||
requires_power = FALSE
|
||||
|
||||
/area/awaymission/spacebattle/cruiser
|
||||
name = "Nanotrasen Cruiser"
|
||||
icon_state = "awaycontent2"
|
||||
|
||||
/area/awaymission/spacebattle/syndicate1
|
||||
name = "Syndicate Assault Ship 1"
|
||||
icon_state = "awaycontent3"
|
||||
|
||||
/area/awaymission/spacebattle/syndicate2
|
||||
name = "Syndicate Assault Ship 2"
|
||||
icon_state = "awaycontent4"
|
||||
|
||||
/area/awaymission/spacebattle/syndicate3
|
||||
name = "Syndicate Assault Ship 3"
|
||||
icon_state = "awaycontent5"
|
||||
|
||||
/area/awaymission/spacebattle/syndicate4
|
||||
name = "Syndicate War Sphere 1"
|
||||
icon_state = "awaycontent6"
|
||||
|
||||
/area/awaymission/spacebattle/syndicate5
|
||||
name = "Syndicate War Sphere 2"
|
||||
icon_state = "awaycontent7"
|
||||
|
||||
/area/awaymission/spacebattle/syndicate6
|
||||
name = "Syndicate War Sphere 3"
|
||||
icon_state = "awaycontent8"
|
||||
|
||||
/area/awaymission/spacebattle/syndicate7
|
||||
name = "Syndicate Fighter"
|
||||
icon_state = "awaycontent9"
|
||||
|
||||
/area/awaymission/spacebattle/secret
|
||||
name = "Hidden Chamber"
|
||||
icon_state = "awaycontent10"
|
||||
|
||||
/mob/living/simple_animal/hostile/syndicate/ranged/spacebattle
|
||||
loot = list(/obj/effect/mob_spawn/human/corpse/syndicatesoldier,
|
||||
/obj/item/gun/ballistic/automatic/c20r,
|
||||
/obj/item/shield/energy)
|
||||
|
||||
/mob/living/simple_animal/hostile/syndicate/melee/spacebattle
|
||||
deathmessage = "falls limp as they release their grip from the energy weapons, activating their self-destruct function!"
|
||||
loot = list(/obj/effect/mob_spawn/human/corpse/syndicatesoldier)
|
||||
@@ -31,7 +31,7 @@
|
||||
description = "CentCom's security forces are going through budget cuts. You will be paid if you ship a set of spears."
|
||||
reward = 1000
|
||||
required_count = 5
|
||||
wanted_types = list(/obj/item/twohanded/spear)
|
||||
wanted_types = list(/obj/item/spear)
|
||||
|
||||
/datum/bounty/item/assistant/toolbox
|
||||
name = "Toolboxes"
|
||||
@@ -134,7 +134,7 @@
|
||||
description = "Central Command is looking to commission a new BirdBoat-class station. You've been ordered to supply the potted plants."
|
||||
reward = 2000
|
||||
required_count = 8
|
||||
wanted_types = list(/obj/item/twohanded/required/kirbyplants)
|
||||
wanted_types = list(/obj/item/kirbyplants)
|
||||
|
||||
// /datum/bounty/item/assistant/earmuffs
|
||||
// name = "Earmuffs"
|
||||
@@ -160,7 +160,7 @@
|
||||
name = "Chainsaw"
|
||||
description = "The chef at CentCom is having trouble butchering her animals. She requests one chainsaw, please."
|
||||
reward = 2500
|
||||
wanted_types = list(/obj/item/twohanded/required/chainsaw)
|
||||
wanted_types = list(/obj/item/chainsaw)
|
||||
|
||||
/datum/bounty/item/assistant/ied
|
||||
name = "IED"
|
||||
|
||||
@@ -22,7 +22,7 @@
|
||||
name = "Bone Axe"
|
||||
description = "Station 12 has had their fire axes stolen by marauding clowns. Ship them a bone axe as a replacement."
|
||||
reward = 3500
|
||||
wanted_types = list(/obj/item/twohanded/fireaxe/boneaxe)
|
||||
wanted_types = list(/obj/item/fireaxe/boneaxe)
|
||||
|
||||
/datum/bounty/item/mining/bone_armor
|
||||
name = "Bone Armor"
|
||||
|
||||
@@ -119,7 +119,7 @@
|
||||
|
||||
/datum/bounty/item/science/noneactive_reactivearmor
|
||||
name = "Reactive Armor Shells"
|
||||
description = "Do to the breakthroughs in anomalies, we can not keep up in making reactive armor shells, can you send us a few?"
|
||||
description = "Due to the breakthroughs in anomalies, we can not keep up in making reactive armor shells, can you send us a few?"
|
||||
reward = 2000
|
||||
required_count = 5
|
||||
wanted_types = list(/obj/item/reactive_armour_shell, /obj/item/clothing/suit/armor/reactive)
|
||||
@@ -138,14 +138,14 @@
|
||||
|
||||
/datum/bounty/item/science/anomaly_neutralizer
|
||||
name = "Anomaly Neutralizers"
|
||||
description = "An idea for a long time was to use an unstable Supermatter Shard to help create the breeding grounds for an unstable part of space to harvest any anomalies we want. It worked a little too well and now were out of anomaly neutralizers please send us a baker's dozen."
|
||||
description = "An idea for a long time was to use an unstable Supermatter Shard to help create the breeding grounds for an unstable part of space to harvest any anomalies we want. It worked a little too well and now we're out of anomaly neutralizers, please send us a baker's dozen."
|
||||
reward = 2500
|
||||
required_count = 13
|
||||
wanted_types = list(/obj/item/anomaly_neutralizer)
|
||||
|
||||
/datum/bounty/item/science/integrated_circuit_printer
|
||||
name = "Integrated Circuit Printer"
|
||||
description = "due to a paperwork error, a newly made integrated circuit manufacturer line is missing three of its printers needed to operate. Until the paper work is corrected we are outsourcing this problem, so please send us three integrated circuit printers."
|
||||
description = "Due to a paperwork error, a newly made integrated circuit manufacturer line is missing three of its printers needed to operate. Until the paper work is corrected we are outsourcing this problem, so please send us three integrated circuit printers."
|
||||
reward = 2000
|
||||
required_count = 3
|
||||
wanted_types = list(/obj/item/integrated_circuit_printer)
|
||||
@@ -159,7 +159,7 @@
|
||||
|
||||
/datum/bounty/item/science/nanite_trash
|
||||
name = "Nanite Based Gear"
|
||||
description = "CC wants to make nanite based gear available to a new wing of devolvement but lacks the hand held tools to get it full up and running. Please send us any you have."
|
||||
description = "CC wants to make nanite based gear available to a new wing of development but lacks the hand held tools to get it fully up and running. Please send us any you have."
|
||||
reward = 2500
|
||||
required_count = 20 //Its just metal
|
||||
wanted_types = list( /obj/item/nanite_remote, /obj/item/nanite_remote/comm, /obj/item/nanite_scanner)
|
||||
|
||||
@@ -18,6 +18,7 @@
|
||||
var/obj/item/radio/headset/radio
|
||||
/// var that tracks message cooldown
|
||||
var/message_cooldown
|
||||
var/list/loaded_coupons
|
||||
|
||||
light_color = "#E2853D"//orange
|
||||
|
||||
@@ -134,6 +135,8 @@
|
||||
"cost" = P.cost,
|
||||
"id" = pack,
|
||||
"desc" = P.desc || P.name, // If there is a description, use it. Otherwise use the pack's name.
|
||||
"private_goody" = P.goody == PACK_GOODY_PRIVATE,
|
||||
"goody" = P.goody == PACK_GOODY_PUBLIC,
|
||||
"access" = P.access,
|
||||
"can_private_buy" = P.can_private_buy
|
||||
))
|
||||
@@ -215,8 +218,22 @@
|
||||
if(isnull(reason) || ..())
|
||||
return
|
||||
|
||||
if(pack.goody == PACK_GOODY_PRIVATE && !self_paid)
|
||||
playsound(src, 'sound/machines/buzz-sigh.ogg', 50, FALSE)
|
||||
say("ERROR: Private small crates may only be purchased by private accounts.")
|
||||
return
|
||||
|
||||
var/obj/item/coupon/applied_coupon
|
||||
for(var/i in loaded_coupons)
|
||||
var/obj/item/coupon/coupon_check = i
|
||||
if(pack.type == coupon_check.discounted_pack)
|
||||
say("Coupon found! [round(coupon_check.discount_pct_off * 100)]% off applied!")
|
||||
coupon_check.moveToNullspace()
|
||||
applied_coupon = coupon_check
|
||||
break
|
||||
|
||||
var/turf/T = get_turf(src)
|
||||
var/datum/supply_order/SO = new(pack, name, rank, ckey, reason, account)
|
||||
var/datum/supply_order/SO = new(pack, name, rank, ckey, reason, account, applied_coupon)
|
||||
SO.generateRequisition(T)
|
||||
if(requestonly && !self_paid)
|
||||
SSshuttle.requestlist += SO
|
||||
@@ -229,6 +246,9 @@
|
||||
var/id = text2num(params["id"])
|
||||
for(var/datum/supply_order/SO in SSshuttle.shoppinglist)
|
||||
if(SO.id == id)
|
||||
if(SO.applied_coupon)
|
||||
say("Coupon refunded.")
|
||||
SO.applied_coupon.forceMove(get_turf(src))
|
||||
SSshuttle.shoppinglist -= SO
|
||||
. = TRUE
|
||||
break
|
||||
|
||||
@@ -0,0 +1,50 @@
|
||||
|
||||
#define COUPON_OMEN "omen"
|
||||
|
||||
/obj/item/coupon
|
||||
name = "coupon"
|
||||
desc = "It doesn't matter if you didn't want it before, what matters now is that you've got a coupon for it!"
|
||||
icon_state = "data_1"
|
||||
icon = 'icons/obj/card.dmi'
|
||||
item_flags = NOBLUDGEON
|
||||
w_class = WEIGHT_CLASS_TINY
|
||||
var/datum/supply_pack/discounted_pack
|
||||
var/discount_pct_off = 0.05
|
||||
var/obj/machinery/computer/cargo/inserted_console
|
||||
|
||||
/// Choose what our prize is :D
|
||||
/obj/item/coupon/proc/generate()
|
||||
discounted_pack = pick(subtypesof(/datum/supply_pack/goody))
|
||||
var/list/chances = list("0.10" = 4, "0.15" = 8, "0.20" = 10, "0.25" = 8, "0.50" = 4, COUPON_OMEN = 1)
|
||||
discount_pct_off = pickweight(chances)
|
||||
if(discount_pct_off == COUPON_OMEN)
|
||||
name = "coupon - fuck you"
|
||||
desc = "The small text reads, 'You will be slaughtered'... That doesn't sound right, does it?"
|
||||
if(ismob(loc))
|
||||
var/mob/M = loc
|
||||
to_chat(M, "<span class='warning'>The coupon reads '<b>fuck you</b>' in large, bold text... is- is that a prize, or?</span>")
|
||||
M.AddComponent(/datum/component/omen, TRUE, src)
|
||||
else
|
||||
discount_pct_off = text2num(discount_pct_off)
|
||||
name = "coupon - [round(discount_pct_off * 100)]% off [initial(discounted_pack.name)]"
|
||||
|
||||
/obj/item/coupon/attack_obj(obj/O, mob/living/user)
|
||||
if(!istype(O, /obj/machinery/computer/cargo))
|
||||
return ..()
|
||||
if(discount_pct_off == COUPON_OMEN)
|
||||
to_chat(user, "<span class='warning'>\The [O] validates the coupon as authentic, but refuses to accept it...</span>")
|
||||
O.say("Coupon fulfillment already in progress...")
|
||||
return
|
||||
|
||||
inserted_console = O
|
||||
LAZYADD(inserted_console.loaded_coupons, src)
|
||||
inserted_console.say("Coupon for [initial(discounted_pack.name)] applied!")
|
||||
forceMove(inserted_console)
|
||||
|
||||
/obj/item/coupon/Destroy()
|
||||
if(inserted_console)
|
||||
LAZYREMOVE(inserted_console.loaded_coupons, src)
|
||||
inserted_console = null
|
||||
. = ..()
|
||||
|
||||
#undef COUPON_OMEN
|
||||
@@ -303,7 +303,7 @@
|
||||
export_types = list(/obj/mecha/combat/durand)
|
||||
|
||||
/datum/export/large/mech/phazon
|
||||
cost = 35000 //Little over half do to needing a core
|
||||
cost = 35000 //Little over half due to needing a core
|
||||
unit_name = "working phazon"
|
||||
export_types = list(/obj/mecha/combat/phazon)
|
||||
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/datum/export/tool
|
||||
k_elasticity = 1/500 //Tool selling almost allways fine a target
|
||||
k_elasticity = 1/500 //Tool selling almost always find a target
|
||||
|
||||
/datum/export/tool/toolbox
|
||||
cost = 6
|
||||
|
||||
@@ -267,7 +267,7 @@
|
||||
/datum/export/weapon/duelsaber
|
||||
cost = 360 //Get it?
|
||||
unit_name = "energy saber"
|
||||
export_types = list(/obj/item/twohanded/dualsaber)
|
||||
export_types = list(/obj/item/dualsaber)
|
||||
|
||||
/datum/export/weapon/esword
|
||||
cost = 130
|
||||
|
||||
+42
-33
@@ -27,10 +27,12 @@
|
||||
var/orderer_rank
|
||||
var/orderer_ckey
|
||||
var/reason
|
||||
var/discounted_pct
|
||||
var/datum/supply_pack/pack
|
||||
var/datum/bank_account/paying_account
|
||||
var/obj/item/coupon/applied_coupon
|
||||
|
||||
/datum/supply_order/New(datum/supply_pack/pack, orderer, orderer_rank, orderer_ckey, reason, paying_account)
|
||||
/datum/supply_order/New(datum/supply_pack/pack, orderer, orderer_rank, orderer_ckey, reason, paying_account, coupon)
|
||||
id = SSshuttle.ordernum++
|
||||
src.pack = pack
|
||||
src.orderer = orderer
|
||||
@@ -38,6 +40,7 @@
|
||||
src.orderer_ckey = orderer_ckey
|
||||
src.reason = reason
|
||||
src.paying_account = paying_account
|
||||
src.applied_coupon = coupon
|
||||
|
||||
/datum/supply_order/proc/generateRequisition(turf/T)
|
||||
var/obj/item/paper/P = new(T)
|
||||
@@ -57,58 +60,64 @@
|
||||
P.update_icon()
|
||||
return P
|
||||
|
||||
/datum/supply_order/proc/generateManifest(obj/structure/closet/crate/C)
|
||||
var/obj/item/paper/fluff/jobs/cargo/manifest/P = new(C, id, pack.cost)
|
||||
/datum/supply_order/proc/generateManifest(obj/container, owner, packname) //generates-the-manifests.
|
||||
var/obj/item/paper/fluff/jobs/cargo/manifest/P = new(container, id, 0)
|
||||
|
||||
var/station_name = (P.errors & MANIFEST_ERROR_NAME) ? new_station_name() : station_name()
|
||||
|
||||
P.name = "shipping manifest - #[id] ([pack.name])"
|
||||
P.name = "shipping manifest - [packname?"#[id] ([pack.name])":"(Grouped Item Crate)"]"
|
||||
P.info += "<h2>[command_name()] Shipping Manifest</h2>"
|
||||
P.info += "<hr/>"
|
||||
if(paying_account)
|
||||
P.info += "Direct purchase from [paying_account.account_holder]<br/>"
|
||||
P.name += " - Purchased by [paying_account.account_holder]"
|
||||
if(id && !(id == "Cargo"))
|
||||
P.info += "Direct purchase from [owner]<br/>"
|
||||
P.name += " - Purchased by [owner]"
|
||||
P.info += "Order #[id]<br/>"
|
||||
P.info += "Destination: [station_name]<br/>"
|
||||
P.info += "Item: [pack.name]<br/>"
|
||||
if(packname)
|
||||
P.info += "Item: [packname]<br/>"
|
||||
P.info += "Contents: <br/>"
|
||||
P.info += "<ul>"
|
||||
for(var/atom/movable/AM in C.contents - P - C.lockerelectronics)
|
||||
var/list/ignore_this = list(P)
|
||||
if(istype(container, /obj/structure/closet))
|
||||
var/obj/structure/closet/C = container
|
||||
ignore_this += C.lockerelectronics
|
||||
for(var/atom/movable/AM in container.contents - ignore_this)
|
||||
if((P.errors & MANIFEST_ERROR_CONTENTS) && prob(50))
|
||||
continue
|
||||
P.info += "<li>[AM.name]</li>"
|
||||
P.info += "</ul>"
|
||||
P.info += "<h4>Stamp below to confirm receipt of goods:</h4>"
|
||||
|
||||
if(P.errors & MANIFEST_ERROR_ITEM)
|
||||
var/static/list/blacklisted_error = typecacheof(list(
|
||||
/obj/structure/closet/crate/secure,
|
||||
/obj/structure/closet/crate/large,
|
||||
/obj/structure/closet/secure_closet/goodies
|
||||
))
|
||||
if(blacklisted_error[container.type])
|
||||
P.errors &= ~MANIFEST_ERROR_ITEM
|
||||
else
|
||||
var/lost = max(round(container.contents.len / 10), 1)
|
||||
while(--lost >= 0)
|
||||
qdel(pick(container.contents))
|
||||
|
||||
P.update_icon()
|
||||
P.forceMove(C)
|
||||
C.manifest = P
|
||||
C.update_icon()
|
||||
P.forceMove(container)
|
||||
|
||||
if(istype(container, /obj/structure/closet/crate))
|
||||
var/obj/structure/closet/crate/C = container
|
||||
C.manifest = P
|
||||
C.update_icon()
|
||||
|
||||
return P
|
||||
|
||||
/datum/supply_order/proc/generate(atom/A)
|
||||
var/obj/structure/closet/crate/C = pack.generate(A, paying_account)
|
||||
var/obj/item/paper/fluff/jobs/cargo/manifest/M = generateManifest(C)
|
||||
|
||||
if(M.errors & MANIFEST_ERROR_ITEM)
|
||||
if(istype(C, /obj/structure/closet/crate/secure) || istype(C, /obj/structure/closet/crate/large))
|
||||
M.errors &= ~MANIFEST_ERROR_ITEM
|
||||
else
|
||||
var/lost = max(round(C.contents.len / 10), 1)
|
||||
while(--lost >= 0)
|
||||
qdel(pick(C.contents))
|
||||
generateManifest(C, paying_account, pack)
|
||||
return C
|
||||
|
||||
//Paperwork for NT
|
||||
/obj/item/folder/paperwork
|
||||
name = "Incomplete Paperwork"
|
||||
desc = "These should've been filled out four months ago! Unfinished grant papers issued by Nanotrasen's finance department. Complete this page for additional funding."
|
||||
icon = 'icons/obj/bureaucracy.dmi'
|
||||
icon_state = "docs_generic"
|
||||
|
||||
/obj/item/folder/paperwork_correct
|
||||
name = "Finished Paperwork"
|
||||
desc = "A neat stack of filled-out forms, in triplicate and signed. Is there anything more satisfying? Make sure they get stamped."
|
||||
icon = 'icons/obj/bureaucracy.dmi'
|
||||
icon_state = "docs_verified"
|
||||
/datum/supply_order/proc/generateCombo(var/miscbox, var/misc_own, var/misc_contents)
|
||||
for (var/I in misc_contents)
|
||||
new I(miscbox)
|
||||
generateManifest(miscbox, misc_own, "")
|
||||
return
|
||||
|
||||
@@ -15,6 +15,7 @@
|
||||
var/special_enabled = FALSE
|
||||
var/DropPodOnly = FALSE //only usable by the Bluespace Drop Pod via the express cargo console
|
||||
var/admin_spawned = FALSE //Can only an admin spawn this crate?
|
||||
var/goody = PACK_GOODY_NONE //Small items can be grouped into a single crate.They also come in a closet/lockbox instead of a full crate, so the 700 min doesn't apply
|
||||
var/can_private_buy = TRUE //Can it be purchased privately by each crewmember?
|
||||
|
||||
/datum/supply_pack/proc/generate(atom/A, datum/bank_account/paying_account)
|
||||
|
||||
@@ -37,15 +37,6 @@
|
||||
contains = list(/obj/item/storage/box/chemimp)
|
||||
crate_name = "chemical implant crate"
|
||||
|
||||
/datum/supply_pack/security/armory/combatknives
|
||||
name = "Combat Knives Crate"
|
||||
desc = "Contains three sharpened combat knives. Each knife guaranteed to fit snugly inside any Nanotrasen-standard boot. Requires Armory access to open."
|
||||
cost = 3200
|
||||
contains = list(/obj/item/kitchen/knife/combat,
|
||||
/obj/item/kitchen/knife/combat,
|
||||
/obj/item/kitchen/knife/combat)
|
||||
crate_name = "combat knife crate"
|
||||
|
||||
/datum/supply_pack/security/armory/ballistic
|
||||
name = "Combat Shotguns Crate"
|
||||
desc = "For when the enemy absolutely needs to be replaced with lead. Contains three Aussec-designed Combat Shotguns, with three Shotgun Bandoliers, as well as seven buchshot and 12g shotgun slugs. Requires Armory access to open."
|
||||
|
||||
@@ -90,16 +90,6 @@
|
||||
crate_name = "industrial rcd"
|
||||
crate_type = /obj/structure/closet/crate/secure/engineering
|
||||
|
||||
/datum/supply_pack/engineering/powergamermitts
|
||||
name = "Insulated Gloves Crate"
|
||||
desc = "The backbone of modern society. Barely ever ordered for actual engineering. Contains three insulated gloves."
|
||||
cost = 2300 //Made of pure-grade bullshittinium
|
||||
contains = list(/obj/item/clothing/gloves/color/yellow,
|
||||
/obj/item/clothing/gloves/color/yellow,
|
||||
/obj/item/clothing/gloves/color/yellow)
|
||||
crate_name = "insulated gloves crate"
|
||||
crate_type = /obj/structure/closet/crate/engineering/electrical
|
||||
|
||||
/datum/supply_pack/engineering/inducers
|
||||
name = "NT-75 Electromagnetic Power Inducers Crate"
|
||||
desc = "No rechargers? No problem, with the NT-75 EPI, you can recharge any standard cell-based equipment anytime, anywhere. Contains two Inducers."
|
||||
@@ -162,6 +152,7 @@
|
||||
/obj/item/storage/toolbox/mechanical)
|
||||
cost = 1200
|
||||
crate_name = "toolbox crate"
|
||||
special = TRUE //Department resupply shuttle loan event.
|
||||
|
||||
/datum/supply_pack/engineering/bsa
|
||||
name = "Bluespace Artillery Parts"
|
||||
|
||||
@@ -0,0 +1,77 @@
|
||||
|
||||
/datum/supply_pack/goody
|
||||
access = NONE
|
||||
group = "Goodies"
|
||||
goody = PACK_GOODY_PRIVATE
|
||||
|
||||
/datum/supply_pack/goody/combatknives_single
|
||||
name = "Combat Knife Single-Pack"
|
||||
desc = "Contains one sharpened combat knive. Guaranteed to fit snugly inside any Nanotrasen-standard boot."
|
||||
cost = 800
|
||||
contains = list(/obj/item/kitchen/knife/combat)
|
||||
|
||||
/datum/supply_pack/goody/sologamermitts
|
||||
name = "Insulated Gloves Single-Pack"
|
||||
desc = "The backbone of modern society. Barely ever ordered for actual engineering."
|
||||
cost = 800
|
||||
contains = list(/obj/item/clothing/gloves/color/yellow)
|
||||
|
||||
/datum/supply_pack/goody/firstaidbruises_single
|
||||
name = "Bruise Treatment Kit Single-Pack"
|
||||
desc = "A single brute first-aid kit, perfect for recovering from being crushed in an airlock. Did you know people get crushed in airlocks all the time? Interesting..."
|
||||
cost = 330
|
||||
contains = list(/obj/item/storage/firstaid/brute)
|
||||
|
||||
/datum/supply_pack/goody/firstaidburns_single
|
||||
name = "Burn Treatment Kit Single-Pack"
|
||||
desc = "A single burn first-aid kit. The advertisement displays a winking atmospheric technician giving a thumbs up, saying \"Mistakes happen!\""
|
||||
cost = 330
|
||||
contains = list(/obj/item/storage/firstaid/fire)
|
||||
|
||||
/datum/supply_pack/goody/firstaid_single
|
||||
name = "First Aid Kit Single-Pack"
|
||||
desc = "A single first-aid kit, fit for healing most types of bodily harm."
|
||||
cost = 250
|
||||
contains = list(/obj/item/storage/firstaid/regular)
|
||||
|
||||
/datum/supply_pack/goody/firstaidoxygen_single
|
||||
name = "Oxygen Deprivation Kit Single-Pack"
|
||||
desc = "A single oxygen deprivation first-aid kit, marketed heavily to those with crippling fears of asphyxiation."
|
||||
cost = 330
|
||||
contains = list(/obj/item/storage/firstaid/o2)
|
||||
|
||||
/datum/supply_pack/goody/firstaidtoxins_single
|
||||
name = "Toxin Treatment Kit Single-Pack"
|
||||
desc = "A single first aid kit focused on healing damage dealt by heavy toxins."
|
||||
cost = 330
|
||||
contains = list(/obj/item/storage/firstaid/toxin)
|
||||
|
||||
/datum/supply_pack/goody/toolbox // mostly just to water down coupon probability
|
||||
name = "Mechanical Toolbox"
|
||||
desc = "A fully stocked mechanical toolbox, for when you're too lazy to just print them out."
|
||||
cost = 300
|
||||
contains = list(/obj/item/storage/toolbox/mechanical)
|
||||
|
||||
/datum/supply_pack/goody/electrical_toolbox // mostly just to water down coupon probability
|
||||
name = "Mechanical Toolbox"
|
||||
desc = "A fully stocked electrical toolbox, for when you're too lazy to just print them out."
|
||||
cost = 300
|
||||
contains = list(/obj/item/storage/toolbox/electrical)
|
||||
|
||||
/datum/supply_pack/goody/valentine
|
||||
name = "Valentine Card"
|
||||
desc = "Make an impression on that special someone! Comes with one valentine card and a free candy heart!"
|
||||
cost = 150
|
||||
contains = list(/obj/item/valentine, /obj/item/reagent_containers/food/snacks/candyheart)
|
||||
|
||||
/datum/supply_pack/goody/beeplush
|
||||
name = "Bee Plushie"
|
||||
desc = "The most important thing you could possibly spend your hard-earned money on."
|
||||
cost = 1500
|
||||
contains = list(/obj/item/toy/plush/beeplushie)
|
||||
|
||||
/datum/supply_pack/goody/beach_ball
|
||||
name = "Beach Ball"
|
||||
desc = "The simple beach ball is one of Nanotrasen's most popular products. 'Why do we make beach balls? Because we can! (TM)' - Nanotrasen"
|
||||
cost = 200
|
||||
contains = list(/obj/item/toy/beach_ball)
|
||||
@@ -14,53 +14,60 @@
|
||||
//////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
/datum/supply_pack/materials/cardboard50
|
||||
goody = PACK_GOODY_PUBLIC
|
||||
name = "50 Cardboard Sheets"
|
||||
desc = "Create a bunch of boxes."
|
||||
cost = 1000
|
||||
cost = 300 //thrice their export value
|
||||
contains = list(/obj/item/stack/sheet/cardboard/fifty)
|
||||
crate_name = "cardboard sheets crate"
|
||||
|
||||
/datum/supply_pack/materials/glass50
|
||||
goody = PACK_GOODY_PUBLIC
|
||||
name = "50 Glass Sheets"
|
||||
desc = "Let some nice light in with fifty glass sheets!"
|
||||
cost = 850
|
||||
cost = 300 //double their export value
|
||||
contains = list(/obj/item/stack/sheet/glass/fifty)
|
||||
crate_name = "glass sheets crate"
|
||||
|
||||
/datum/supply_pack/materials/metal50
|
||||
goody = PACK_GOODY_PUBLIC
|
||||
name = "50 Metal Sheets"
|
||||
desc = "Any construction project begins with a good stack of fifty metal sheets!"
|
||||
cost = 850
|
||||
cost = 300 //double their export value
|
||||
contains = list(/obj/item/stack/sheet/metal/fifty)
|
||||
crate_name = "metal sheets crate"
|
||||
|
||||
/datum/supply_pack/materials/plasteel20
|
||||
goody = PACK_GOODY_PUBLIC
|
||||
name = "20 Plasteel Sheets"
|
||||
desc = "Reinforce the station's integrity with twenty plasteel sheets!"
|
||||
cost = 4700
|
||||
cost = 4000
|
||||
contains = list(/obj/item/stack/sheet/plasteel/twenty)
|
||||
crate_name = "plasteel sheets crate"
|
||||
|
||||
/datum/supply_pack/materials/plasteel50
|
||||
name = "50 Plasteel Sheets"
|
||||
desc = "For when you REALLY have to reinforce something."
|
||||
cost = 9050
|
||||
contains = list(/obj/item/stack/sheet/plasteel/fifty)
|
||||
crate_name = "plasteel sheets crate"
|
||||
|
||||
/datum/supply_pack/materials/plastic50
|
||||
goody = PACK_GOODY_PUBLIC
|
||||
name = "50 Plastic Sheets"
|
||||
desc = "Build a limitless amount of toys with fifty plastic sheets!"
|
||||
cost = 950
|
||||
contains = list(/obj/item/stack/sheet/plastic/fifty)
|
||||
crate_name = "plastic sheets crate"
|
||||
cost = 200 // double their export
|
||||
contains = list(/obj/item/stack/sheet/plastic/twenty)
|
||||
|
||||
/datum/supply_pack/materials/sandstone30
|
||||
goody = PACK_GOODY_PUBLIC
|
||||
name = "30 Sandstone Blocks"
|
||||
desc = "Neither sandy nor stoney, these thirty blocks will still get the job done."
|
||||
cost = 800
|
||||
cost = 150 // five times their export
|
||||
contains = list(/obj/item/stack/sheet/mineral/sandstone/thirty)
|
||||
crate_name = "sandstone blocks crate"
|
||||
|
||||
/datum/supply_pack/materials/wood50
|
||||
goody = PACK_GOODY_PUBLIC
|
||||
name = "50 Wood Planks"
|
||||
desc = "Turn cargo's boring metal groundwork into beautiful panelled flooring and much more with fifty wooden planks!"
|
||||
cost = 400 // 6-7 planks shy from having equal import/export prices
|
||||
contains = list(/obj/item/stack/sheet/mineral/wood/twenty)
|
||||
|
||||
/datum/supply_pack/materials/rcdammo
|
||||
goody = PACK_GOODY_PUBLIC
|
||||
name = "Large RCD ammo Single-Pack"
|
||||
desc = "A single large compressed RCD matter pack, to help with any holes or projects people might be working on."
|
||||
cost = 600
|
||||
contains = list(/obj/item/rcd_ammo/large)
|
||||
|
||||
/datum/supply_pack/materials/rawlumber
|
||||
name = "50 Towercap Logs"
|
||||
@@ -74,35 +81,6 @@
|
||||
for(var/i in 1 to 49)
|
||||
new /obj/item/grown/log(.)
|
||||
|
||||
/datum/supply_pack/materials/wood50
|
||||
name = "50 Wood Planks"
|
||||
desc = "Turn cargo's boring metal groundwork into beautiful panelled flooring and much more with fifty wooden planks!"
|
||||
cost = 1450
|
||||
contains = list(/obj/item/stack/sheet/mineral/wood/fifty)
|
||||
crate_name = "wood planks crate"
|
||||
|
||||
/datum/supply_pack/materials/rcdammo
|
||||
name = "Spare RCD ammo"
|
||||
desc = "This crate contains sixteen RCD compressed matter packs, to help with any holes or projects people might be working on."
|
||||
cost = 3750
|
||||
contains = list(/obj/item/rcd_ammo,
|
||||
/obj/item/rcd_ammo,
|
||||
/obj/item/rcd_ammo,
|
||||
/obj/item/rcd_ammo,
|
||||
/obj/item/rcd_ammo,
|
||||
/obj/item/rcd_ammo,
|
||||
/obj/item/rcd_ammo,
|
||||
/obj/item/rcd_ammo,
|
||||
/obj/item/rcd_ammo,
|
||||
/obj/item/rcd_ammo,
|
||||
/obj/item/rcd_ammo,
|
||||
/obj/item/rcd_ammo,
|
||||
/obj/item/rcd_ammo,
|
||||
/obj/item/rcd_ammo,
|
||||
/obj/item/rcd_ammo,
|
||||
/obj/item/rcd_ammo)
|
||||
crate_name = "rcd ammo"
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////////
|
||||
///////////////////////////// Canisters //////////////////////////////////////
|
||||
//////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
@@ -141,34 +141,6 @@
|
||||
///////////////////////////// Medical Kits ///////////////////////////////////
|
||||
//////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
/datum/supply_pack/medical/firstaidbruises
|
||||
name = "Bruise Treatment Kit Crate"
|
||||
desc = "Contains three first aid kits focused on healing bruises and broken bones."
|
||||
cost = 1000
|
||||
contains = list(/obj/item/storage/firstaid/brute,
|
||||
/obj/item/storage/firstaid/brute,
|
||||
/obj/item/storage/firstaid/brute)
|
||||
crate_name = "brute treatment kit crate"
|
||||
|
||||
/datum/supply_pack/medical/firstaidburns
|
||||
name = "Burn Treatment Kit Crate"
|
||||
desc = "Contains three first aid kits focused on healing severe burns."
|
||||
cost = 1000
|
||||
contains = list(/obj/item/storage/firstaid/fire,
|
||||
/obj/item/storage/firstaid/fire,
|
||||
/obj/item/storage/firstaid/fire)
|
||||
crate_name = "burn treatment kit crate"
|
||||
|
||||
/datum/supply_pack/medical/firstaid
|
||||
name = "First Aid Kit Crate"
|
||||
desc = "Contains four first aid kits for healing most types of wounds."
|
||||
cost = 1000
|
||||
contains = list(/obj/item/storage/firstaid/regular,
|
||||
/obj/item/storage/firstaid/regular,
|
||||
/obj/item/storage/firstaid/regular,
|
||||
/obj/item/storage/firstaid/regular)
|
||||
crate_name = "first aid kit crate"
|
||||
|
||||
/datum/supply_pack/medical/sprays
|
||||
name = "Medical Sprays"
|
||||
desc = "Contains two cans of Styptic Spray, Silver Sulfadiazine Spray, Synthflesh Spray and Sterilizer Compound Spray."
|
||||
@@ -183,35 +155,6 @@
|
||||
/obj/item/reagent_containers/medspray/sterilizine)
|
||||
crate_name = "medical supplies crate"
|
||||
|
||||
/datum/supply_pack/medical/firstaidmixed
|
||||
name = "Mixed Medical Kits"
|
||||
desc = "Contains one of each medical kits for dealing with a variety of injured crewmembers."
|
||||
cost = 1250
|
||||
contains = list(/obj/item/storage/firstaid/toxin,
|
||||
/obj/item/storage/firstaid/o2,
|
||||
/obj/item/storage/firstaid/brute,
|
||||
/obj/item/storage/firstaid/fire,
|
||||
/obj/item/storage/firstaid/regular)
|
||||
crate_name = "medical supplies crate"
|
||||
|
||||
/datum/supply_pack/medical/firstaidoxygen
|
||||
name = "Oxygen Deprivation Kit Crate"
|
||||
desc = "Contains three first aid kits focused on helping oxygen deprivation victims."
|
||||
cost = 1000
|
||||
contains = list(/obj/item/storage/firstaid/o2,
|
||||
/obj/item/storage/firstaid/o2,
|
||||
/obj/item/storage/firstaid/o2)
|
||||
crate_name = "oxygen deprivation kit crate"
|
||||
|
||||
/datum/supply_pack/medical/firstaidtoxins
|
||||
name = "Toxin Treatment Kit Crate"
|
||||
desc = "Contains three first aid kits focused on healing damage dealt by heavy toxins."
|
||||
cost = 1000
|
||||
contains = list(/obj/item/storage/firstaid/toxin,
|
||||
/obj/item/storage/firstaid/toxin,
|
||||
/obj/item/storage/firstaid/toxin)
|
||||
crate_name = "toxin treatment kit crate"
|
||||
|
||||
/datum/supply_pack/medical/advrad
|
||||
name = "Radiation Treatment Crate Deluxe"
|
||||
desc = "A crate for when radiation is out of hand... Contains two rad-b-gone kits, one bottle of anti radiation deluxe pills, as well as a radiation treatment deluxe pill bottle!"
|
||||
|
||||
@@ -294,11 +294,11 @@
|
||||
name = "Potted Plants Crate"
|
||||
desc = "Spruce up the station with these lovely plants! Contains a random assortment of five potted plants from Nanotrasen's potted plant research division. Warranty void if thrown."
|
||||
cost = 730
|
||||
contains = list(/obj/item/twohanded/required/kirbyplants/random,
|
||||
/obj/item/twohanded/required/kirbyplants/random,
|
||||
/obj/item/twohanded/required/kirbyplants/random,
|
||||
/obj/item/twohanded/required/kirbyplants/random,
|
||||
/obj/item/twohanded/required/kirbyplants/random)
|
||||
contains = list(/obj/item/kirbyplants/random,
|
||||
/obj/item/kirbyplants/random,
|
||||
/obj/item/kirbyplants/random,
|
||||
/obj/item/kirbyplants/random,
|
||||
/obj/item/kirbyplants/random)
|
||||
crate_name = "potted plants crate"
|
||||
crate_type = /obj/structure/closet/crate/hydroponics
|
||||
|
||||
@@ -333,45 +333,58 @@
|
||||
//////////////////////////// Misc + Decor ////////////////////////////////////
|
||||
//////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
/datum/supply_pack/misc/carpet_exotic
|
||||
name = "Exotic Carpet Crate"
|
||||
desc = "Exotic carpets straight from Space Russia, for all your decorating needs. Contains 100 tiles each of 10 different flooring patterns."
|
||||
cost = 7000
|
||||
contains = list(/obj/item/stack/tile/carpet/blue/fifty,
|
||||
/obj/item/stack/tile/carpet/blue/fifty,
|
||||
/obj/item/stack/tile/carpet/cyan/fifty,
|
||||
/obj/item/stack/tile/carpet/cyan/fifty,
|
||||
/obj/item/stack/tile/carpet/green/fifty,
|
||||
/obj/item/stack/tile/carpet/green/fifty,
|
||||
/obj/item/stack/tile/carpet/orange/fifty,
|
||||
/obj/item/stack/tile/carpet/orange/fifty,
|
||||
/obj/item/stack/tile/carpet/purple/fifty,
|
||||
/obj/item/stack/tile/carpet/purple/fifty,
|
||||
/obj/item/stack/tile/carpet/red/fifty,
|
||||
/obj/item/stack/tile/carpet/red/fifty,
|
||||
/obj/item/stack/tile/carpet/royalblue/fifty,
|
||||
/obj/item/stack/tile/carpet/royalblue/fifty,
|
||||
/obj/item/stack/tile/carpet/royalblack/fifty,
|
||||
/obj/item/stack/tile/carpet/royalblack/fifty,
|
||||
/obj/item/stack/tile/carpet/blackred/fifty,
|
||||
/obj/item/stack/tile/carpet/blackred/fifty,
|
||||
/obj/item/stack/tile/carpet/monochrome/fifty,
|
||||
/obj/item/stack/tile/carpet/monochrome/fifty)
|
||||
crate_name = "exotic carpet crate"
|
||||
|
||||
/datum/supply_pack/misc/carpet
|
||||
name = "Premium Carpet Crate"
|
||||
desc = "Plasteel floor tiles getting on your nerves? These stacks of extra soft carpet will tie any room together. Contains some classic carpet, along with black, red, and monochrome varients."
|
||||
cost = 1350
|
||||
contains = list(/obj/item/stack/tile/carpet/fifty,
|
||||
/obj/item/stack/tile/carpet/fifty,
|
||||
/obj/item/stack/tile/carpet/black/fifty,
|
||||
/obj/item/stack/tile/carpet/black/fifty,
|
||||
/obj/item/stack/tile/carpet/blackred/fifty,
|
||||
/obj/item/stack/tile/carpet/blackred/fifty,
|
||||
/obj/item/stack/tile/carpet/monochrome/fifty,
|
||||
/obj/item/stack/tile/carpet/monochrome/fifty)
|
||||
crate_name = "premium carpet crate"
|
||||
goody = PACK_GOODY_PUBLIC
|
||||
name = "Classic Carpet Single-Pack"
|
||||
desc = "Plasteel floor tiles getting on your nerves? This 50 units stack of extra soft carpet will tie any room together."
|
||||
cost = 200
|
||||
contains = list(/obj/item/stack/tile/carpet/fifty)
|
||||
|
||||
/datum/supply_pack/misc/carpet/black
|
||||
name = "Black Carpet Single-Pack"
|
||||
contains = list(/obj/item/stack/tile/carpet/black/fifty)
|
||||
|
||||
/datum/supply_pack/misc/carpet/premium
|
||||
name = "Monochrome Carpet Single-Pack"
|
||||
desc = "Exotic carpets for all your decorating needs. This 30 units stack of extra soft carpet will tie any room together."
|
||||
cost = 250
|
||||
contains = list(/obj/item/stack/tile/carpet/monochrome/thirty)
|
||||
|
||||
/datum/supply_pack/misc/carpet/premium/blackred
|
||||
name = "Black-Red Carpet Single-Pack"
|
||||
contains = list(/obj/item/stack/tile/carpet/blackred/thirty)
|
||||
|
||||
/datum/supply_pack/misc/carpet/premium/royalblack
|
||||
name = "Royal Black Carpet Single-Pack"
|
||||
contains = list(/obj/item/stack/tile/carpet/royalblack/thirty)
|
||||
|
||||
/datum/supply_pack/misc/carpet/premium/royalblue
|
||||
name = "Royal Blue Carpet Single-Pack"
|
||||
contains = list(/obj/item/stack/tile/carpet/royalblue/thirty)
|
||||
|
||||
/datum/supply_pack/misc/carpet/premium/red
|
||||
name = "Red Carpet Single-Pack"
|
||||
contains = list(/obj/item/stack/tile/carpet/red/thirty)
|
||||
|
||||
/datum/supply_pack/misc/carpet/premium/purple
|
||||
name = "Purple Carpet Single-Pack"
|
||||
contains = list(/obj/item/stack/tile/carpet/purple/thirty)
|
||||
|
||||
/datum/supply_pack/misc/carpet/premium/orange
|
||||
name = "Orange Carpet Single-Pack"
|
||||
contains = list(/obj/item/stack/tile/carpet/orange/thirty)
|
||||
|
||||
/datum/supply_pack/misc/carpet/premium/green
|
||||
name = "Green Carpet Single-Pack"
|
||||
contains = list(/obj/item/stack/tile/carpet/green/thirty)
|
||||
|
||||
/datum/supply_pack/misc/carpet/premium/cyan
|
||||
name = "Cyan Carpet Single-Pack"
|
||||
contains = list(/obj/item/stack/tile/carpet/cyan/thirty)
|
||||
|
||||
/datum/supply_pack/misc/carpet/premium/blue
|
||||
name = "Blue Carpet Single-Pack"
|
||||
contains = list(/obj/item/stack/tile/carpet/blue/thirty)
|
||||
|
||||
/datum/supply_pack/misc/noslipfloor
|
||||
name = "High-traction Floor Tiles"
|
||||
@@ -417,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)
|
||||
|
||||
|
||||
@@ -19,6 +19,8 @@
|
||||
///Next tick to reset the total message counter
|
||||
var/total_count_reset = 0
|
||||
var/ircreplyamount = 0
|
||||
/// last time they tried to do an autobunker auth
|
||||
var/autobunker_last_try = 0
|
||||
|
||||
/////////
|
||||
//OTHER//
|
||||
@@ -133,3 +135,14 @@
|
||||
var/parallax_movedir = 0
|
||||
var/parallax_layers_max = 3
|
||||
var/parallax_animate_timer
|
||||
|
||||
// List of all asset filenames sent to this client by the asset cache, along with their assoicated md5s
|
||||
var/list/sent_assets = list()
|
||||
/// List of all completed blocking send jobs awaiting acknowledgement by send_asset
|
||||
var/list/completed_asset_jobs = list()
|
||||
/// Last asset send job id.
|
||||
var/last_asset_job = 0
|
||||
var/last_completed_asset_job = 0
|
||||
|
||||
//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)
|
||||
@@ -265,9 +268,7 @@ GLOBAL_LIST_EMPTY(external_rsc_urls)
|
||||
else
|
||||
prefs = new /datum/preferences(src)
|
||||
GLOB.preferences_datums[ckey] = prefs
|
||||
if(SSinput.initialized)
|
||||
set_macros()
|
||||
update_movement_keys(prefs)
|
||||
addtimer(CALLBACK(src, .proc/ensure_keys_set), 0) //prevents possible race conditions
|
||||
|
||||
prefs.last_ip = address //these are gonna be used for banning
|
||||
prefs.last_id = computer_id //these are gonna be used for banning
|
||||
@@ -461,6 +462,11 @@ GLOBAL_LIST_EMPTY(external_rsc_urls)
|
||||
|
||||
Master.UpdateTickRate()
|
||||
|
||||
/client/proc/ensure_keys_set()
|
||||
if(SSinput.initialized)
|
||||
set_macros()
|
||||
update_movement_keys(prefs)
|
||||
|
||||
//////////////
|
||||
//DISCONNECT//
|
||||
//////////////
|
||||
@@ -858,8 +864,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]
|
||||
|
||||
@@ -162,6 +162,8 @@ GLOBAL_LIST_EMPTY(preferences_datums)
|
||||
"body_model" = MALE,
|
||||
"body_size" = RESIZE_DEFAULT_SIZE
|
||||
)
|
||||
var/custom_speech_verb = "default" //if your say_mod is to be something other than your races
|
||||
var/custom_tongue = "default" //if your tongue is to be something other than your races
|
||||
|
||||
var/list/custom_names = list()
|
||||
var/preferred_ai_core_display = "Blue"
|
||||
@@ -440,6 +442,13 @@ GLOBAL_LIST_EMPTY(preferences_datums)
|
||||
else if(use_skintones || mutant_colors)
|
||||
dat += "</td>"
|
||||
|
||||
dat += APPEARANCE_CATEGORY_COLUMN
|
||||
dat += "<h2>Speech preferences</h2>"
|
||||
dat += "<b>Custom Speech Verb:</b><BR>"
|
||||
dat += "</b><a style='display:block;width:100px' href='?_src_=prefs;preference=speech_verb;task=input'>[custom_speech_verb]</a><BR>"
|
||||
dat += "<b>Custom Tongue:</b><BR>"
|
||||
dat += "</b><a style='display:block;width:100px' href='?_src_=prefs;preference=tongue;task=input'>[custom_tongue]</a><BR>"
|
||||
|
||||
if(HAIR in pref_species.species_traits)
|
||||
|
||||
dat += APPEARANCE_CATEGORY_COLUMN
|
||||
@@ -1638,19 +1647,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
|
||||
@@ -2323,7 +2332,14 @@ GLOBAL_LIST_EMPTY(preferences_datums)
|
||||
new_body_size = danger
|
||||
if(dorfy != "No")
|
||||
features["body_size"] = new_body_size
|
||||
|
||||
if("tongue")
|
||||
var/selected_custom_tongue = input(user, "Choose your desired tongue (none means your species tongue)", "Character Preference") as null|anything in GLOB.roundstart_tongues
|
||||
if(selected_custom_tongue)
|
||||
custom_tongue = selected_custom_tongue
|
||||
if("speech_verb")
|
||||
var/selected_custom_speech_verb = input(user, "Choose your desired speech verb (none means your species speech verb)", "Character Preference") as null|anything in GLOB.speech_verbs
|
||||
if(selected_custom_speech_verb)
|
||||
custom_speech_verb = selected_custom_speech_verb
|
||||
else
|
||||
switch(href_list["preference"])
|
||||
//CITADEL PREFERENCES EDIT - I can't figure out how to modularize these, so they have to go here. :c -Pooj
|
||||
@@ -2720,6 +2736,19 @@ GLOBAL_LIST_EMPTY(preferences_datums)
|
||||
|
||||
character.dna.update_body_size(old_size)
|
||||
|
||||
//speech stuff
|
||||
if(custom_tongue != "default")
|
||||
var/new_tongue = GLOB.roundstart_tongues[custom_tongue]
|
||||
if(new_tongue)
|
||||
var/obj/item/organ/tongue/T = character.getorganslot(ORGAN_SLOT_TONGUE)
|
||||
if(T)
|
||||
qdel(T)
|
||||
var/obj/item/organ/tongue/new_custom_tongue = new new_tongue
|
||||
new_custom_tongue.Insert(character)
|
||||
if(custom_speech_verb != "default")
|
||||
character.dna.species.say_mod = custom_speech_verb
|
||||
|
||||
|
||||
SEND_SIGNAL(character, COMSIG_HUMAN_PREFS_COPIED_TO, src, icon_updates, roundstart_checks)
|
||||
|
||||
//let's be sure the character updates
|
||||
|
||||
@@ -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
|
||||
@@ -195,6 +195,11 @@ SAVEFILE UPDATING/VERSIONING - 'Simplified', or rather, more coder-friendly ~Car
|
||||
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)
|
||||
return
|
||||
@@ -474,6 +479,8 @@ SAVEFILE UPDATING/VERSIONING - 'Simplified', or rather, more coder-friendly ~Car
|
||||
S["backbag"] >> backbag
|
||||
S["jumpsuit_style"] >> jumpsuit_style
|
||||
S["uplink_loc"] >> uplink_spawn_loc
|
||||
S["custom_speech_verb"] >> custom_speech_verb
|
||||
S["custom_tongue"] >> custom_tongue
|
||||
S["feature_mcolor"] >> features["mcolor"]
|
||||
S["feature_lizard_tail"] >> features["tail_lizard"]
|
||||
S["feature_lizard_snout"] >> features["snout"]
|
||||
@@ -688,6 +695,8 @@ SAVEFILE UPDATING/VERSIONING - 'Simplified', or rather, more coder-friendly ~Car
|
||||
features["balls_visibility"] = sanitize_inlist(features["balls_visibility"], safe_visibilities, GEN_VISIBLE_NO_UNDIES)
|
||||
features["vag_visibility"] = sanitize_inlist(features["vag_visibility"], safe_visibilities, GEN_VISIBLE_NO_UNDIES)
|
||||
|
||||
custom_speech_verb = sanitize_inlist(custom_speech_verb, GLOB.speech_verbs, "default")
|
||||
custom_tongue = sanitize_inlist(custom_tongue, GLOB.roundstart_tongues, "default")
|
||||
|
||||
features["flavor_text"] = copytext(features["flavor_text"], 1, MAX_FLAVOR_LEN)
|
||||
features["silicon_flavor_text"] = copytext(features["silicon_flavor_text"], 1, MAX_FLAVOR_LEN)
|
||||
@@ -751,6 +760,8 @@ SAVEFILE UPDATING/VERSIONING - 'Simplified', or rather, more coder-friendly ~Car
|
||||
WRITE_FILE(S["jumpsuit_style"] , jumpsuit_style)
|
||||
WRITE_FILE(S["uplink_loc"] , uplink_spawn_loc)
|
||||
WRITE_FILE(S["species"] , pref_species.id)
|
||||
WRITE_FILE(S["custom_speech_verb"] , custom_speech_verb)
|
||||
WRITE_FILE(S["custom_tongue"] , custom_tongue)
|
||||
WRITE_FILE(S["feature_mcolor"] , features["mcolor"])
|
||||
WRITE_FILE(S["feature_lizard_tail"] , features["tail_lizard"])
|
||||
WRITE_FILE(S["feature_human_tail"] , features["tail_human"])
|
||||
|
||||
@@ -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
|
||||
|
||||
|
||||
@@ -0,0 +1,37 @@
|
||||
/client/verb/bunker_auto_authorize()
|
||||
set name = "Auto Authorize Panic Bunker"
|
||||
set desc = "Authorizes your account in the panic bunker of any servers connected to this function."
|
||||
set category = "OOC"
|
||||
|
||||
if(autobunker_last_try + 5 SECONDS > world.time)
|
||||
to_chat(src, "<span class='danger'>Function on cooldown, try again in 5 seconds.</span>")
|
||||
return
|
||||
autobunker_last_try = world.time
|
||||
|
||||
world.send_cross_server_bunker_overrides(key, src)
|
||||
|
||||
/world/proc/send_cross_server_bunker_overrides(key, client/C)
|
||||
var/comms_key = CONFIG_GET(string/comms_key)
|
||||
if(!comms_key)
|
||||
return
|
||||
var/list/message = list()
|
||||
message["ckey"] = key
|
||||
message["source"] = "[CONFIG_GET(string/cross_comms_name)]"
|
||||
message["key"] = comms_key
|
||||
message["auto_bunker_override"] = TRUE
|
||||
var/list/servers = CONFIG_GET(keyed_list/cross_server_bunker_override)
|
||||
if(!length(servers))
|
||||
to_chat(C, "<span class='boldwarning'>AUTOBUNKER: No servers are configured to receive from this one.</span>")
|
||||
return
|
||||
log_admin("[key] ([key_name(C)]) has initiated an autobunker authentication with linked servers.")
|
||||
for(var/name in servers)
|
||||
var/returned = world.Export("[servers[name]]?[list2params(message)]")
|
||||
switch(returned)
|
||||
if("Bad Key")
|
||||
to_chat(C, "<span class='boldwarning'>AUTOBuNKER: [name] failed to authenticate with this server.</span>")
|
||||
if("Function Disabled")
|
||||
to_chat(C, "<span class='boldwarning'>AUTOBUNKER: [name] has autobunker receive disabled.</span>")
|
||||
if("Success")
|
||||
to_chat(C, "<span class='boldwarning'>AUTOBUNKER: Successfully authenticated with [name]. Panic bunker bypass granted to [key].</span>.")
|
||||
else
|
||||
to_chat(C, "<span class='boldwarning'>AUTOBUNKER: Unknown error ([name]).</span>")
|
||||
@@ -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)
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -23,14 +23,15 @@
|
||||
if(iscarbon(target) && proximity)
|
||||
var/mob/living/carbon/C = target
|
||||
var/mob/living/carbon/U = user
|
||||
var/success = C.equip_to_slot_if_possible(new /obj/item/clothing/gloves/color/yellow/sprayon, ITEM_SLOT_GLOVES, TRUE, TRUE)
|
||||
var/success = C.equip_to_slot_if_possible(new /obj/item/clothing/gloves/color/yellow/sprayon, ITEM_SLOT_GLOVES, TRUE, TRUE, clothing_check = TRUE)
|
||||
if(success)
|
||||
if(C == user)
|
||||
C.visible_message("<span class='notice'>[U] sprays their hands with glittery rubber!</span>")
|
||||
else
|
||||
C.visible_message("<span class='warning'>[U] sprays glittery rubber on the hands of [C]!</span>")
|
||||
else
|
||||
C.visible_message("<span class='warning'>The rubber fails to stick to [C]'s hands!</span>")
|
||||
user.visible_message("<span class='warning'>The rubber fails to stick to [C]'s hands!</span>",
|
||||
"<span class='warning'>The rubber fails to stick to [C]'s [(SLOT_GLOVES in C.check_obscured_slots()) ? "unexposed" : ""] hands!</span>")
|
||||
|
||||
qdel(src)
|
||||
|
||||
|
||||
@@ -74,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
|
||||
@@ -244,7 +244,7 @@
|
||||
icon_state = "knight_greyscale"
|
||||
item_state = "knight_greyscale"
|
||||
armor = list("melee" = 35, "bullet" = 10, "laser" = 10, "energy" = 10, "bomb" = 10, "bio" = 10, "rad" = 10, "fire" = 40, "acid" = 40)
|
||||
material_flags = MATERIAL_ADD_PREFIX | MATERIAL_COLOR | MATERIAL_AFFECT_STATISTICS | MATERIAL_EFFECTS //Can change color and add prefix
|
||||
material_flags = MATERIAL_ADD_PREFIX | MATERIAL_COLOR | MATERIAL_AFFECT_STATISTICS //Can change color and add prefix
|
||||
|
||||
/obj/item/clothing/head/helmet/skull
|
||||
name = "skull 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,20 @@
|
||||
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
|
||||
|
||||
/obj/item/clothing/head/kepi
|
||||
name = "kepi"
|
||||
desc = "A white cap with visor. Oui oui, mon capitane!"
|
||||
icon_state = "kepi"
|
||||
|
||||
/obj/item/clothing/head/kepi/old
|
||||
icon_state = "kepi_old"
|
||||
desc = "A flat, white circular cap with a visor, that demands some honor from it's wearer."
|
||||
|
||||
@@ -238,7 +238,7 @@
|
||||
item_state = "foilhat"
|
||||
armor = list("melee" = 0, "bullet" = 0, "laser" = -5,"energy" = 0, "bomb" = 0, "bio" = 0, "rad" = -5, "fire" = 0, "acid" = 0)
|
||||
equip_delay_other = 140
|
||||
var/datum/brain_trauma/mild/phobia/paranoia
|
||||
var/datum/brain_trauma/mild/phobia/conspiracies/paranoia
|
||||
var/warped = FALSE
|
||||
clothing_flags = IGNORE_HAT_TOSS
|
||||
|
||||
@@ -255,7 +255,8 @@
|
||||
return
|
||||
if(paranoia)
|
||||
QDEL_NULL(paranoia)
|
||||
paranoia = new("conspiracies")
|
||||
paranoia = new()
|
||||
paranoia.clonable = FALSE
|
||||
user.gain_trauma(paranoia, TRAUMA_RESILIENCE_MAGIC)
|
||||
to_chat(user, "<span class='warning'>As you don the foiled hat, an entire world of conspiracy theories and seemingly insane ideas suddenly rush into your mind. What you once thought unbelievable suddenly seems.. undeniable. Everything is connected and nothing happens just by accident. You know too much and now they're out to get you. </span>")
|
||||
|
||||
|
||||
@@ -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"
|
||||
|
||||
@@ -123,7 +123,7 @@
|
||||
l_pocket = /obj/item/reagent_containers/food/snacks/grown/banana
|
||||
r_pocket = /obj/item/bikehorn
|
||||
id = /obj/item/card/id
|
||||
r_hand = /obj/item/twohanded/fireaxe
|
||||
r_hand = /obj/item/fireaxe
|
||||
|
||||
/datum/outfit/tunnel_clown/post_equip(mob/living/carbon/human/H, visualsOnly = FALSE, client/preference_source)
|
||||
if(visualsOnly)
|
||||
@@ -148,7 +148,7 @@
|
||||
suit = /obj/item/clothing/suit/apron
|
||||
l_pocket = /obj/item/kitchen/knife
|
||||
r_pocket = /obj/item/scalpel
|
||||
r_hand = /obj/item/twohanded/fireaxe
|
||||
r_hand = /obj/item/fireaxe
|
||||
|
||||
/datum/outfit/psycho/post_equip(mob/living/carbon/human/H, visualsOnly = FALSE, client/preference_source)
|
||||
for(var/obj/item/carried_item in H.get_equipped_items(TRUE))
|
||||
|
||||
@@ -18,6 +18,7 @@
|
||||
mutantrace_variation = STYLE_DIGITIGRADE
|
||||
var/last_bloodtype = "" //used to track the last bloodtype to have graced these shoes; makes for better performing footprint shenanigans
|
||||
var/last_blood_DNA = "" //same as last one
|
||||
var/last_blood_color = ""
|
||||
|
||||
/obj/item/clothing/shoes/ComponentInitialize()
|
||||
. = ..()
|
||||
@@ -48,6 +49,7 @@
|
||||
if(blood_dna.len)
|
||||
last_bloodtype = blood_dna[blood_dna[blood_dna.len]]//trust me this works
|
||||
last_blood_DNA = blood_dna[blood_dna.len]
|
||||
last_blood_color = blood_dna["color"]
|
||||
|
||||
/obj/item/clothing/shoes/worn_overlays(isinhands = FALSE, icon_file, used_state, style_flags = NONE)
|
||||
. = ..()
|
||||
|
||||
@@ -84,7 +84,7 @@
|
||||
user.alpha = 255
|
||||
user.update_atom_colour()
|
||||
user.animate_movement = FORWARD_STEPS
|
||||
user.notransform = 0
|
||||
user.mob_transforming = 0
|
||||
user.anchored = FALSE
|
||||
teleporting = 0
|
||||
for(var/obj/item/I in user.held_items)
|
||||
@@ -125,7 +125,7 @@
|
||||
ADD_TRAIT(I, TRAIT_NODROP, CHRONOSUIT_TRAIT)
|
||||
user.animate_movement = NO_STEPS
|
||||
user.changeNext_move(8 + phase_in_ds)
|
||||
user.notransform = 1
|
||||
user.mob_transforming = 1
|
||||
user.anchored = TRUE
|
||||
user.Stun(INFINITY)
|
||||
|
||||
|
||||
@@ -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
|
||||
|
||||
|
||||
@@ -286,7 +286,7 @@
|
||||
icon_state = "knight_greyscale"
|
||||
item_state = "knight_greyscale"
|
||||
armor = list("melee" = 35, "bullet" = 10, "laser" = 10, "energy" = 10, "bomb" = 10, "bio" = 10, "rad" = 10, "fire" = 40, "acid" = 40)
|
||||
material_flags = MATERIAL_ADD_PREFIX | MATERIAL_COLOR | MATERIAL_AFFECT_STATISTICS | MATERIAL_EFFECTS //Can change color and add prefix
|
||||
material_flags = MATERIAL_ADD_PREFIX | MATERIAL_COLOR | MATERIAL_AFFECT_STATISTICS //Can change color and add prefix
|
||||
|
||||
/obj/item/clothing/suit/armor/vest/durathread
|
||||
name = "makeshift vest"
|
||||
|
||||
@@ -59,7 +59,7 @@
|
||||
name = "goliath cloak"
|
||||
icon_state = "goliath_cloak"
|
||||
desc = "A staunch, practical cape made out of numerous monster materials, it is coveted amongst exiles & hermits."
|
||||
allowed = list(/obj/item/flashlight, /obj/item/tank/internals, /obj/item/pickaxe, /obj/item/twohanded/spear, /obj/item/twohanded/bonespear, /obj/item/organ/regenerative_core/legion, /obj/item/kitchen/knife/combat/bone, /obj/item/kitchen/knife/combat/survival)
|
||||
allowed = list(/obj/item/flashlight, /obj/item/tank/internals, /obj/item/pickaxe, /obj/item/spear, /obj/item/spear/bonespear, /obj/item/organ/regenerative_core/legion, /obj/item/kitchen/knife/combat/bone, /obj/item/kitchen/knife/combat/survival)
|
||||
armor = list("melee" = 35, "bullet" = 10, "laser" = 25, "energy" = 10, "bomb" = 25, "bio" = 0, "rad" = 0, "fire" = 60, "acid" = 60) //a fair alternative to bone armor, requiring alternative materials and gaining a suit slot
|
||||
hoodtype = /obj/item/clothing/head/hooded/cloakhood/goliath
|
||||
body_parts_covered = CHEST|ARMS|LEGS
|
||||
@@ -75,7 +75,7 @@
|
||||
name = "drake armour"
|
||||
icon_state = "dragon"
|
||||
desc = "A suit of armour fashioned from the remains of an ash drake."
|
||||
allowed = list(/obj/item/flashlight, /obj/item/tank/internals, /obj/item/resonator, /obj/item/mining_scanner, /obj/item/t_scanner/adv_mining_scanner, /obj/item/gun/energy/kinetic_accelerator, /obj/item/pickaxe, /obj/item/twohanded/spear)
|
||||
allowed = list(/obj/item/flashlight, /obj/item/tank/internals, /obj/item/resonator, /obj/item/mining_scanner, /obj/item/t_scanner/adv_mining_scanner, /obj/item/gun/energy/kinetic_accelerator, /obj/item/pickaxe, /obj/item/spear)
|
||||
armor = list("melee" = 70, "bullet" = 20, "laser" = 35, "energy" = 25, "bomb" = 25, "bio" = 0, "rad" = 0, "fire" = 100, "acid" = 100)
|
||||
hoodtype = /obj/item/clothing/head/hooded/cloakhood/drake
|
||||
heat_protection = CHEST|GROIN|LEGS|FEET|ARMS|HANDS
|
||||
|
||||
@@ -537,7 +537,7 @@
|
||||
|
||||
/obj/item/clothing/suit/hooded/wintercoat/captain
|
||||
name = "captain's winter coat"
|
||||
desc = "A luxuriant winter coat, stuffed with the down of the endangered Uka bird and trimmed with genuine sable. The fabric is an indulgently soft micro-fiber, and the deep ultramarine color is only one that could be achieved with minute amounts of crystalline bluespace dust woven into the thread between the plectrums. Extremely lavish, and extremely durable. The tiny flakes of protective material make it nothing short of extremely light lamellar armor."
|
||||
desc = "A luxurious winter coat, stuffed with the down of the endangered Uka bird and trimmed with genuine sable. The fabric is an indulgently soft micro-fiber, and the deep ultramarine color is only one that could be achieved with minute amounts of crystalline bluespace dust woven into the thread between the plectrums. Extremely lavish, and extremely durable. The tiny flakes of protective material make it nothing short of extremely light lamellar armor."
|
||||
icon_state = "coatcaptain"
|
||||
item_state = "coatcaptain"
|
||||
armor = list("melee" = 25, "bullet" = 30, "laser" = 30, "energy" = 10, "bomb" = 25, "bio" = 0, "rad" = 0, "fire" = 0, "acid" = 50)
|
||||
@@ -565,7 +565,7 @@
|
||||
|
||||
/obj/item/clothing/suit/hooded/wintercoat/security
|
||||
name = "security winter coat"
|
||||
desc = "A red, armor-padded winter coat. It glitters with a mild ablative coating and a robust air of authority. The zipper tab is a pair of jingly little handcuffs and got annoying after the first ten seconds."
|
||||
desc = "A red, armor-padded winter coat. It glitters with a mild ablative coating and a robust air of authority. The zipper tab is a pair of jingly little handcuffs that get annoying after the first ten seconds."
|
||||
icon_state = "coatsecurity"
|
||||
item_state = "coatsecurity"
|
||||
armor = list("melee" = 25, "bullet" = 15, "laser" = 30, "energy" = 10, "bomb" = 25, "bio" = 0, "rad" = 0, "fire" = 0, "acid" = 45)
|
||||
@@ -867,7 +867,7 @@
|
||||
icon_state = "coatnarsie"
|
||||
item_state = "coatnarsie"
|
||||
armor = list("melee" = 30, "bullet" = 20, "laser" = 30,"energy" = 10, "bomb" = 30, "bio" = 10, "rad" = 10, "fire" = 30, "acid" = 30)
|
||||
allowed = list(/obj/item/flashlight, /obj/item/tank/internals/emergency_oxygen, /obj/item/tank/internals/plasmaman, /obj/item/toy, /obj/item/storage/fancy/cigarettes, /obj/item/lighter, /obj/item/restraints/legcuffs/bola/cult,/obj/item/melee/cultblade,/obj/item/melee/cultblade/dagger,/obj/item/reagent_containers/glass/beaker/unholywater,/obj/item/cult_shift,/obj/item/flashlight/flare/culttorch,/obj/item/twohanded/cult_spear)
|
||||
allowed = list(/obj/item/flashlight, /obj/item/tank/internals/emergency_oxygen, /obj/item/tank/internals/plasmaman, /obj/item/toy, /obj/item/storage/fancy/cigarettes, /obj/item/lighter, /obj/item/restraints/legcuffs/bola/cult,/obj/item/melee/cultblade,/obj/item/melee/cultblade/dagger,/obj/item/reagent_containers/glass/beaker/unholywater,/obj/item/cult_shift,/obj/item/flashlight/flare/culttorch,/obj/item/cult_spear)
|
||||
hoodtype = /obj/item/clothing/head/hooded/winterhood/narsie
|
||||
var/real = TRUE
|
||||
|
||||
@@ -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"
|
||||
|
||||
@@ -164,7 +164,7 @@
|
||||
RemoveHelmet()
|
||||
..()
|
||||
|
||||
/obj/item/clothing/suit/space/hardsuit/proc/RemoveHelmet()
|
||||
/obj/item/clothing/suit/space/hardsuit/proc/RemoveHelmet(message = TRUE)
|
||||
if(!helmet)
|
||||
return
|
||||
suittoggled = FALSE
|
||||
@@ -174,16 +174,18 @@
|
||||
helmet.attack_self(H)
|
||||
H.transferItemToLoc(helmet, src, TRUE)
|
||||
H.update_inv_wear_suit()
|
||||
to_chat(H, "<span class='notice'>The helmet on the hardsuit disengages.</span>")
|
||||
if(message)
|
||||
to_chat(H, "<span class='notice'>The helmet on the hardsuit disengages.</span>")
|
||||
playsound(src.loc, 'sound/mecha/mechmove03.ogg', 50, 1)
|
||||
else
|
||||
helmet.forceMove(src)
|
||||
return TRUE
|
||||
|
||||
/obj/item/clothing/suit/space/hardsuit/dropped(mob/user)
|
||||
..()
|
||||
RemoveHelmet()
|
||||
|
||||
/obj/item/clothing/suit/space/hardsuit/proc/ToggleHelmet()
|
||||
/obj/item/clothing/suit/space/hardsuit/proc/ToggleHelmet(message = TRUE)
|
||||
var/mob/living/carbon/human/H = loc
|
||||
if(!helmettype)
|
||||
return
|
||||
@@ -192,15 +194,19 @@
|
||||
if(!suittoggled)
|
||||
if(ishuman(src.loc))
|
||||
if(H.wear_suit != src)
|
||||
to_chat(H, "<span class='warning'>You must be wearing [src] to engage the helmet!</span>")
|
||||
if(message)
|
||||
to_chat(H, "<span class='warning'>You must be wearing [src] to engage the helmet!</span>")
|
||||
return
|
||||
if(H.head)
|
||||
to_chat(H, "<span class='warning'>You're already wearing something on your head!</span>")
|
||||
if(message)
|
||||
to_chat(H, "<span class='warning'>You're already wearing something on your head!</span>")
|
||||
return
|
||||
else if(H.equip_to_slot_if_possible(helmet,SLOT_HEAD,0,0,1))
|
||||
to_chat(H, "<span class='notice'>You engage the helmet on the hardsuit.</span>")
|
||||
if(message)
|
||||
to_chat(H, "<span class='notice'>You engage the helmet on the hardsuit.</span>")
|
||||
suittoggled = TRUE
|
||||
H.update_inv_wear_suit()
|
||||
playsound(src.loc, 'sound/mecha/mechmove03.ogg', 50, 1)
|
||||
return TRUE
|
||||
else
|
||||
RemoveHelmet()
|
||||
return RemoveHelmet(message)
|
||||
|
||||
@@ -46,4 +46,4 @@
|
||||
icon_state = "lewdcap"
|
||||
item_state = "lewdcap"
|
||||
can_adjust = FALSE
|
||||
mutantrace_variation = USE_TAUR_CLIP_MASK
|
||||
mutantrace_variation = STYLE_DIGITIGRADE|USE_TAUR_CLIP_MASK
|
||||
|
||||
@@ -22,7 +22,7 @@
|
||||
icon_state = "cmoturtle"
|
||||
item_state = "w_suit"
|
||||
alt_covers_chest = TRUE
|
||||
mutantrace_variation = USE_TAUR_CLIP_MASK
|
||||
mutantrace_variation = STYLE_DIGITIGRADE|USE_TAUR_CLIP_MASK
|
||||
|
||||
/obj/item/clothing/under/rank/medical/geneticist
|
||||
desc = "It's made of a special fiber that gives special protection against biohazards. It has a genetics rank stripe on it."
|
||||
|
||||
@@ -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
|
||||
@@ -17,9 +17,9 @@
|
||||
|
||||
var/holidayID = "" //string which should be in the SSeventss.holidays list if you wish this event to be holiday-specific
|
||||
//anything with a (non-null) holidayID which does not match holiday, cannot run.
|
||||
var/wizardevent = 0
|
||||
|
||||
var/alertadmins = 1 //should we let the admins know this event is firing
|
||||
var/wizardevent = FALSE
|
||||
var/random = FALSE //If the event has occured randomly, or if it was forced by an admin or in-game occurance
|
||||
var/alert_observers = TRUE //should we let the ghosts and admins know this event is firing
|
||||
//should be disabled on events that fire a lot
|
||||
|
||||
var/list/gamemode_blacklist = list() // Event won't happen in these gamemodes
|
||||
@@ -33,7 +33,7 @@
|
||||
min_players = CEILING(min_players * CONFIG_GET(number/events_min_players_mul), 1)
|
||||
|
||||
/datum/round_event_control/wizard
|
||||
wizardevent = 1
|
||||
wizardevent = TRUE
|
||||
var/can_be_midround_wizard = TRUE
|
||||
|
||||
// Checks if the event can be spawned. Used by event controller and "false alarm" event.
|
||||
@@ -67,7 +67,7 @@
|
||||
return EVENT_CANT_RUN
|
||||
|
||||
triggering = TRUE
|
||||
if (alertadmins)
|
||||
if (alert_observers)
|
||||
message_admins("Random Event triggering in 10 seconds: [name] (<a href='?src=[REF(src)];cancel=1'>CANCEL</a>)")
|
||||
sleep(100)
|
||||
var/gamemode = SSticker.mode.config_tag
|
||||
@@ -92,7 +92,7 @@
|
||||
log_admin_private("[key_name(usr)] cancelled event [name].")
|
||||
SSblackbox.record_feedback("tally", "event_admin_cancelled", 1, typepath)
|
||||
|
||||
/datum/round_event_control/proc/runEvent(random)
|
||||
/datum/round_event_control/proc/runEvent()
|
||||
var/datum/round_event/E = new typepath()
|
||||
E.current_players = get_active_player_count(alive_check = 1, afk_check = 1, human_check = 1)
|
||||
E.control = src
|
||||
@@ -101,10 +101,9 @@
|
||||
|
||||
testing("[time2text(world.time, "hh:mm:ss")] [E.type]")
|
||||
if(random)
|
||||
if(alertadmins)
|
||||
deadchat_broadcast("<span class='deadsay'><b>[name]</b> has just been randomly triggered!</span>") //STOP ASSUMING IT'S BADMINS!
|
||||
log_game("Random Event triggering: [name] ([typepath])")
|
||||
|
||||
if (alert_observers)
|
||||
deadchat_broadcast("<span class='deadsay'><b>[name]</b> has just been[random ? " randomly" : ""] triggered!</span>") //STOP ASSUMING IT'S BADMINS!
|
||||
return E
|
||||
|
||||
//Special admins setup
|
||||
@@ -140,6 +139,17 @@
|
||||
/datum/round_event/proc/start()
|
||||
return
|
||||
|
||||
/**
|
||||
* Called after something followable has been spawned by an event
|
||||
* Provides ghosts a follow link to an atom if possible
|
||||
* Only called once.
|
||||
*/
|
||||
/datum/round_event/proc/announce_to_ghosts(atom/atom_of_interest)
|
||||
if(control.alert_observers)
|
||||
if (atom_of_interest)
|
||||
notify_ghosts("[control.name] has an object of interest: [atom_of_interest]!", source=atom_of_interest, action=NOTIFY_ORBIT, header="Something's Interesting!")
|
||||
return
|
||||
|
||||
//Called when the tick is equal to the announceWhen variable.
|
||||
//Allows you to announce before starting or vice versa.
|
||||
//Only called once.
|
||||
|
||||
@@ -8,7 +8,7 @@
|
||||
|
||||
/datum/round_event/anomaly
|
||||
var/area/impact_area
|
||||
var/obj/effect/anomaly/newAnomaly
|
||||
var/obj/effect/anomaly/anomaly_path = /obj/effect/anomaly/flux
|
||||
announceWhen = 1
|
||||
|
||||
|
||||
@@ -27,7 +27,7 @@
|
||||
|
||||
//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
|
||||
|
||||
return safepick(typecache_filter_list(GLOB.sortedAreas,allowed_areas))
|
||||
@@ -44,6 +44,9 @@
|
||||
priority_announce("Localized energetic flux wave detected on long range scanners. Expected location of impact: [impact_area.name].", "Anomaly Alert")
|
||||
|
||||
/datum/round_event/anomaly/start()
|
||||
var/turf/T = safepick(get_area_turfs(impact_area))
|
||||
var/turf/T = pick(get_area_turfs(impact_area))
|
||||
var/newAnomaly
|
||||
if(T)
|
||||
newAnomaly = new /obj/effect/anomaly/flux(T)
|
||||
newAnomaly = new anomaly_path(T)
|
||||
if (newAnomaly)
|
||||
announce_to_ghosts(newAnomaly)
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
/datum/round_event_control/anomaly/anomaly_bluespace
|
||||
name = "Anomaly: Bluespace"
|
||||
typepath = /datum/round_event/anomaly/anomaly_bluespace
|
||||
|
||||
max_occurrences = 1
|
||||
weight = 5
|
||||
gamemode_blacklist = list("dynamic")
|
||||
@@ -8,15 +9,10 @@
|
||||
/datum/round_event/anomaly/anomaly_bluespace
|
||||
startWhen = 3
|
||||
announceWhen = 10
|
||||
|
||||
anomaly_path = /obj/effect/anomaly/bluespace
|
||||
|
||||
/datum/round_event/anomaly/anomaly_bluespace/announce(fake)
|
||||
if(prob(90))
|
||||
priority_announce("Unstable bluespace anomaly detected on long range scanners. Expected location: [impact_area.name].", "Anomaly Alert")
|
||||
else
|
||||
print_command_report("Unstable bluespace anomaly detected on long range scanners. Expected location: [impact_area.name].", "Unstable bluespace anomaly")
|
||||
|
||||
/datum/round_event/anomaly/anomaly_bluespace/start()
|
||||
var/turf/T = safepick(get_area_turfs(impact_area))
|
||||
if(T)
|
||||
newAnomaly = new /obj/effect/anomaly/bluespace(T)
|
||||
|
||||
@@ -10,14 +10,10 @@
|
||||
/datum/round_event/anomaly/anomaly_flux
|
||||
startWhen = 10
|
||||
announceWhen = 3
|
||||
anomaly_path = /obj/effect/anomaly/flux
|
||||
|
||||
/datum/round_event/anomaly/anomaly_flux/announce(fake)
|
||||
if(prob(90))
|
||||
priority_announce("Localized hyper-energetic flux wave detected on long range scanners. Expected location: [impact_area.name].", "Anomaly Alert")
|
||||
else
|
||||
print_command_report("Localized hyper-energetic flux wave detected on long range scanners. Expected location: [impact_area.name].","Localized hyper-energetic flux wave")
|
||||
|
||||
/datum/round_event/anomaly/anomaly_flux/start()
|
||||
var/turf/T = safepick(get_area_turfs(impact_area))
|
||||
if(T)
|
||||
newAnomaly = new /obj/effect/anomaly/flux(T)
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
/datum/round_event_control/anomaly/anomaly_grav
|
||||
name = "Anomaly: Gravitational"
|
||||
typepath = /datum/round_event/anomaly/anomaly_grav
|
||||
|
||||
max_occurrences = 5
|
||||
weight = 20
|
||||
gamemode_blacklist = list("dynamic")
|
||||
@@ -9,14 +10,10 @@
|
||||
/datum/round_event/anomaly/anomaly_grav
|
||||
startWhen = 3
|
||||
announceWhen = 20
|
||||
anomaly_path = /obj/effect/anomaly/grav
|
||||
|
||||
/datum/round_event/anomaly/anomaly_grav/announce(fake)
|
||||
if(prob(90))
|
||||
priority_announce("Gravitational anomaly detected on long range scanners. Expected location: [impact_area.name].", "Anomaly Alert")
|
||||
else
|
||||
print_command_report("Gravitational anomaly detected on long range scanners. Expected location: [impact_area.name].", "Gravitational anomaly")
|
||||
|
||||
/datum/round_event/anomaly/anomaly_grav/start()
|
||||
var/turf/T = safepick(get_area_turfs(impact_area))
|
||||
if(T)
|
||||
newAnomaly = new /obj/effect/anomaly/grav(T)
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
/datum/round_event_control/anomaly/anomaly_pyro
|
||||
name = "Anomaly: Pyroclastic"
|
||||
typepath = /datum/round_event/anomaly/anomaly_pyro
|
||||
|
||||
max_occurrences = 5
|
||||
weight = 20
|
||||
gamemode_blacklist = list("dynamic")
|
||||
@@ -8,14 +9,10 @@
|
||||
/datum/round_event/anomaly/anomaly_pyro
|
||||
startWhen = 3
|
||||
announceWhen = 10
|
||||
anomaly_path = /obj/effect/anomaly/pyro
|
||||
|
||||
/datum/round_event/anomaly/anomaly_pyro/announce(fake)
|
||||
if(prob(90))
|
||||
priority_announce("Pyroclastic anomaly detected on long range scanners. Expected location: [impact_area.name].", "Anomaly Alert")
|
||||
else
|
||||
print_command_report("Pyroclastic anomaly detected on long range scanners. Expected location: [impact_area.name].", "Pyroclastic anomaly")
|
||||
|
||||
/datum/round_event/anomaly/anomaly_pyro/start()
|
||||
var/turf/T = safepick(get_area_turfs(impact_area))
|
||||
if(T)
|
||||
newAnomaly = new /obj/effect/anomaly/pyro(T)
|
||||
|
||||
@@ -10,14 +10,10 @@
|
||||
/datum/round_event/anomaly/anomaly_vortex
|
||||
startWhen = 10
|
||||
announceWhen = 3
|
||||
anomaly_path = /obj/effect/anomaly/bhole
|
||||
|
||||
/datum/round_event/anomaly/anomaly_vortex/announce(fake)
|
||||
if(prob(90))
|
||||
priority_announce("Localized high-intensity vortex anomaly detected on long range scanners. Expected location: [impact_area.name]", "Anomaly Alert")
|
||||
else
|
||||
print_command_report("Localized high-intensity vortex anomaly detected on long range scanners. Expected location: [impact_area.name].","Vortex anomaly")
|
||||
|
||||
/datum/round_event/anomaly/anomaly_vortex/start()
|
||||
var/turf/T = safepick(get_area_turfs(impact_area))
|
||||
if(T)
|
||||
newAnomaly = new /obj/effect/anomaly/bhole(T)
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user