Revert "?"

This reverts commit c6b5bac0d8.
This commit is contained in:
EmeraldSundisk
2020-07-04 21:39:23 -07:00
parent c6b5bac0d8
commit 45a14f16d4
871 changed files with 96125 additions and 411183 deletions
+1 -1
View File
@@ -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
+1 -1
View File
@@ -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.")
+70 -45
View File
@@ -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'>&nbsp;</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'>&nbsp;</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'>&nbsp;</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'>&nbsp;</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 ..()
+1 -1
View File
@@ -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))
+42 -23
View File
@@ -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)
+3 -2
View File
@@ -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)
+169
View File
@@ -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 -1
View File
@@ -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
+100
View File
@@ -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
+228
View 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)
@@ -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)
+17 -12
View File
@@ -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))
+1 -1
View File
@@ -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)
+3 -3
View File
@@ -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"
+1 -1
View File
@@ -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"
+4 -4
View File
@@ -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)
+21 -1
View File
@@ -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
+50
View File
@@ -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
+1 -1
View File
@@ -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 -1
View File
@@ -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
+1 -1
View File
@@ -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
View File
@@ -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
+1
View File
@@ -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)
-9
View File
@@ -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."
+1 -10
View File
@@ -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"
+77
View File
@@ -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)
+27 -49
View File
@@ -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 //////////////////////////////////////
//////////////////////////////////////////////////////////////////////////////
-57
View File
@@ -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!"
+93 -43
View File
@@ -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)
+32
View File
@@ -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)
+13
View File
@@ -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
+37 -25
View File
@@ -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]
+36 -7
View File
@@ -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
+12 -1
View File
@@ -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"])
+28 -11
View File
@@ -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
+37
View File
@@ -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>")
+6 -2
View File
@@ -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)
+3 -1
View File
@@ -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
+3 -2
View File
@@ -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)
+5 -1
View File
@@ -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
+7 -1
View File
@@ -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 = ""
+17
View File
@@ -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."
+3 -2
View File
@@ -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>")
+13
View File
@@ -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
+6
View File
@@ -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"
+2 -2
View File
@@ -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))
+2
View File
@@ -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
+1 -1
View File
@@ -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"
+2 -2
View File
@@ -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
+9 -3
View File
@@ -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"
+13 -7
View File
@@ -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)
+1 -1
View File
@@ -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
+1 -1
View File
@@ -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
+19 -9
View File
@@ -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.
+7 -4
View File
@@ -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)
+2 -6
View File
@@ -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)
+1 -5
View File
@@ -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)
+2 -5
View File
@@ -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)
+2 -5
View File
@@ -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)
+1 -5
View File
@@ -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