This commit is contained in:
Ghommie
2020-06-29 06:55:35 +02:00
540 changed files with 87486 additions and 406619 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
@@ -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"]
@@ -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
@@ -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
@@ -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
@@ -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
@@ -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
+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
@@ -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,9 @@
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(!(. = ..()))
return
if(stasis)
return
if(revealed && essence <= 0)
@@ -120,14 +122,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 +219,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 +261,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 +272,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 +321,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)
@@ -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
+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,58 @@
/client
var/list/sent_assets = list() // List of all asset filenames sent to this client by the asset cache, along with their assoicated md5s
var/list/completed_asset_jobs = list() /// List of all completed blocking send jobs awaiting acknowledgement by send_asset
var/last_asset_job = 0 /// Last asset send job id.
var/last_completed_asset_job = 0
/// Process asset cache client topic calls for "asset_cache_confirm_arrival=[INT]"
/client/proc/asset_cache_confirm_arrival(job_id)
var/asset_cache_job = round(text2num(job_id))
//because we skip the limiter, we have to make sure this is a valid arrival and not somebody tricking us into letting them append to a list without limit.
if (asset_cache_job > 0 && asset_cache_job <= last_asset_job && !(completed_asset_jobs["[asset_cache_job]"]))
completed_asset_jobs["[asset_cache_job]"] = TRUE
last_completed_asset_job = max(last_completed_asset_job, asset_cache_job)
else
return asset_cache_job || TRUE
/// Process asset cache client topic calls for "asset_cache_preload_data=[HTML+JSON_STRING]
/client/proc/asset_cache_preload_data(data)
/*var/jsonend = findtextEx(data, "{{{ENDJSONDATA}}}")
if (!jsonend)
CRASH("invalid asset_cache_preload_data, no jsonendmarker")*/
//var/json = html_decode(copytext(data, 1, jsonend))
var/json = data
var/list/preloaded_assets = json_decode(json)
for (var/preloaded_asset in preloaded_assets)
if (copytext(preloaded_asset, findlasttext(preloaded_asset, ".")+1) in list("js", "jsm", "htm", "html"))
preloaded_assets -= preloaded_asset
continue
sent_assets |= preloaded_assets
/// Updates the client side stored html/json combo file used to keep track of what assets the client has between restarts/reconnects.
/client/proc/asset_cache_update_json(verify = FALSE, list/new_assets = list())
if (world.time - connection_time < 10 SECONDS) //don't override the existing data file on a new connection
return
if (!islist(new_assets))
new_assets = list("[new_assets]" = md5(SSassets.cache[new_assets]))
src << browse(json_encode(new_assets|sent_assets), "file=asset_data.json&display=0")
/// Blocks until all currently sending browser assets have been sent.
/// Due to byond limitations, this proc will sleep for 1 client round trip even if the client has no pending asset sends.
/// This proc will return an untrue value if it had to return before confirming the send, such as timeout or the client going away.
/client/proc/asset_flush(timeout = 50)
var/job = ++last_asset_job
var/t = 0
var/timeout_time = timeout
src << browse({"<script>window.location.href="?asset_cache_confirm_arrival=[job]"</script>"}, "window=asset_cache_browser&file=asset_cache_send_verify.htm")
while(!completed_asset_jobs["[job]"] && t < timeout_time) // Reception is handled in Topic()
stoplag(1) // Lock up the caller until this is received.
t++
if (t < timeout_time)
return TRUE
@@ -0,0 +1,21 @@
/**
* # asset_cache_item
*
* An internal datum containing info on items in the asset cache. Mainly used to cache md5 info for speed.
**/
/datum/asset_cache_item
var/name
var/md5
var/resource
/datum/asset_cache_item/New(name, file)
if (!isfile(file))
file = fcopy_rsc(file)
md5 = md5(file)
if (!md5)
md5 = md5(fcopy_rsc(file))
if (!md5)
CRASH("invalid asset sent to asset cache")
debug_world_log("asset cache unexpected success of second fcopy_rsc")
src.name = name
resource = file
+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>
@@ -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/twohanded/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
@@ -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)
+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
+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!"
+88 -38
View File
@@ -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)
+31 -22
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)
@@ -858,8 +861,14 @@ GLOBAL_LIST_EMPTY(external_rsc_urls)
'html/browser/playeroptions.css',
)
spawn (10) //removing this spawn causes all clients to not get verbs.
//load info on what assets the client has
src << browse('code/modules/asset_cache/validate_assets.html', "window=asset_cache_browser")
//Precache the client with all other assets slowly, so as to not block other browse() calls
getFilesSlow(src, SSassets.preload, register_asset = FALSE)
addtimer(CALLBACK(GLOBAL_PROC, /proc/getFilesSlow, src, SSassets.preload, FALSE), 5 SECONDS)
#if (PRELOAD_RSC == 0)
for (var/name in GLOB.vox_sounds)
var/file = GLOB.vox_sounds[name]
+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
+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
+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
+6
View File
@@ -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."
+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
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)
@@ -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
@@ -1016,3 +1016,9 @@
/obj/item/clothing/head/hooded/winterhood/polychromic
icon_state = "winterhood_poly"
item_state = "winterhood_poly"
/obj/item/clothing/suit/striped_sweater
name = "striped sweater"
desc = "Reminds you of someone, but you just can't put your finger on it..."
icon_state = "waldo_shirt"
item_state = "waldo_shirt"
@@ -192,3 +192,14 @@
icon_state = "hos_parade_fem"
item_state = "r_suit"
fitted = FEMALE_UNIFORM_TOP
/*
*Spacepol
*/
/obj/item/clothing/under/rank/security/spacepol
name = "police uniform"
desc = "Space not controlled by megacorporations, planets, or pirates is under the jurisdiction of Spacepol."
icon_state = "spacepol"
item_state = "spacepol"
can_adjust = FALSE
+33
View File
@@ -0,0 +1,33 @@
/datum/round_event_control/brain_trauma
name = "Spontaneous Brain Trauma"
typepath = /datum/round_event/brain_trauma
weight = 25
/datum/round_event/brain_trauma
fakeable = FALSE
/datum/round_event/brain_trauma/start()
for(var/mob/living/carbon/human/H in shuffle(GLOB.alive_mob_list))
if(!H.client)
continue
if(H.stat == DEAD) // What are you doing in this list
continue
if(!H.getorgan(/obj/item/organ/brain)) // If only I had a brain
continue
traumatize(H)
break
/datum/round_event/brain_trauma/proc/traumatize(mob/living/carbon/human/H)
var/resistance = pick(
65;TRAUMA_RESILIENCE_BASIC,
30;TRAUMA_RESILIENCE_SURGERY,
5;TRAUMA_RESILIENCE_LOBOTOMY)
var/trauma_type = pickweight(list(
BRAIN_TRAUMA_MILD = 60,
BRAIN_TRAUMA_SEVERE = 30,
BRAIN_TRAUMA_SPECIAL = 10
))
H.gain_trauma_type(trauma_type, resistance)
+30
View File
@@ -0,0 +1,30 @@
/datum/round_event_control/fake_virus
name = "Fake Virus"
typepath = /datum/round_event/fake_virus
weight = 20
/datum/round_event/fake_virus/start()
var/list/fake_virus_victims = list()
for(var/mob/living/carbon/human/H in shuffle(GLOB.player_list))
if(!H.client || H.stat == DEAD || H.InCritical())
continue
fake_virus_victims += H
//first we do hard status effect victims
var/defacto_min = min(3, LAZYLEN(fake_virus_victims))
if(defacto_min)// event will hit 1-3 people by default, but will do 1-2 or just 1 if only those many candidates are available
for(var/i=1; i<=rand(1,defacto_min); i++)
var/mob/living/carbon/human/hypochondriac = pick(fake_virus_victims)
hypochondriac.apply_status_effect(STATUS_EFFECT_FAKE_VIRUS)
fake_virus_victims -= hypochondriac
//then we do light one-message victims who simply cough or whatever once (have to repeat the process since the last operation modified our candidates list)
defacto_min = min(5, LAZYLEN(fake_virus_victims))
if(defacto_min)
for(var/i=1; i<=rand(1,defacto_min); i++)
var/mob/living/carbon/human/onecoughman = pick(fake_virus_victims)
if(prob(25))//1/4 odds to get a spooky message instead of coughing out loud
addtimer(CALLBACK(GLOBAL_PROC, .proc/to_chat, onecoughman, "<span class='warning'>[pick("Your head hurts.", "Your head pounds.")]</span>"), rand(30,150))
else
addtimer(CALLBACK(onecoughman, .mob/proc/emote, pick("cough", "sniff", "sneeze")), rand(30,150))//deliver the message with a slightly randomized time interval so there arent multiple people coughing at the exact same time
fake_virus_victims -= onecoughman
+117
View File
@@ -0,0 +1,117 @@
/datum/round_event_control/fugitives
name = "Spawn Fugitives"
typepath = /datum/round_event/ghost_role/fugitives
max_occurrences = 1
min_players = 20
earliest_start = 30 MINUTES //deadchat sink, lets not even consider it early on.
gamemode_blacklist = list("nuclear")
/datum/round_event/ghost_role/fugitives
minimum_required = 1
role_name = "fugitive"
fakeable = FALSE
/datum/round_event/ghost_role/fugitives/spawn_role()
var/list/possible_spawns = list()//Some xeno spawns are in some spots that will instantly kill the refugees, like atmos
for(var/turf/X in GLOB.xeno_spawn)
if(istype(X.loc, /area/maintenance))
possible_spawns += X
if(!possible_spawns.len)
message_admins("No valid spawn locations found, aborting...")
return MAP_ERROR
var/turf/landing_turf = pick(possible_spawns)
var/list/possible_backstories = list()
var/list/candidates = get_candidates(ROLE_TRAITOR, null, ROLE_TRAITOR)
if(candidates.len >= 1) //solo refugees
if(prob(30))
possible_backstories.Add("waldo") //less common as it comes with magicks and is kind of immershun shattering
else //For accurate deadchat feedback
minimum_required = 4
if(candidates.len >= 4)//group refugees
possible_backstories.Add("prisoner", "cultist", "synth")
if(!possible_backstories.len)
return NOT_ENOUGH_PLAYERS
var/backstory = pick(possible_backstories)
var/member_size = 3
var/leader
switch(backstory)
if("synth")
leader = pick_n_take(candidates)
if("waldo")
member_size = 0 //solo refugees have no leader so the member_size gets bumped to one a bit later
var/list/members = list()
var/list/spawned_mobs = list()
if(isnull(leader))
member_size++ //if there is no leader role, then the would be leader is a normal member of the team.
for(var/i in 1 to member_size)
members += pick_n_take(candidates)
for(var/mob/dead/selected in members)
var/mob/living/carbon/human/S = gear_fugitive(selected, landing_turf, backstory)
spawned_mobs += S
if(!isnull(leader))
gear_fugitive_leader(leader, landing_turf, backstory)
//after spawning
playsound(src, 'sound/weapons/emitter.ogg', 50, TRUE)
new /obj/item/storage/toolbox/mechanical(landing_turf) //so they can actually escape maint
addtimer(CALLBACK(src, .proc/spawn_hunters), 10 MINUTES)
role_name = "fugitive hunter"
return SUCCESSFUL_SPAWN
/datum/round_event/ghost_role/fugitives/proc/gear_fugitive(mob/dead/selected, turf/landing_turf, backstory) //spawns normal fugitive
var/datum/mind/player_mind = new /datum/mind(selected.key)
player_mind.active = TRUE
var/mob/living/carbon/human/S = new(landing_turf)
player_mind.transfer_to(S)
player_mind.assigned_role = "Fugitive"
player_mind.special_role = "Fugitive"
player_mind.add_antag_datum(/datum/antagonist/fugitive)
var/datum/antagonist/fugitive/fugitiveantag = player_mind.has_antag_datum(/datum/antagonist/fugitive)
INVOKE_ASYNC(fugitiveantag, /datum/antagonist/fugitive.proc/greet, backstory) //some fugitives have a sleep on their greet, so we don't want to stop the entire antag granting proc with fluff
switch(backstory)
if("prisoner")
S.equipOutfit(/datum/outfit/prisoner)
if("cultist")
S.equipOutfit(/datum/outfit/yalp_cultist)
if("waldo")
S.equipOutfit(/datum/outfit/waldo)
if("synth")
S.equipOutfit(/datum/outfit/synthetic)
message_admins("[ADMIN_LOOKUPFLW(S)] has been made into a Fugitive by an event.")
log_game("[key_name(S)] was spawned as a Fugitive by an event.")
spawned_mobs += S
return S
//special spawn for one member. it can be used for a special mob or simply to give one normal member special items.
/datum/round_event/ghost_role/fugitives/proc/gear_fugitive_leader(mob/dead/leader, turf/landing_turf, backstory)
var/datum/mind/player_mind = new /datum/mind(leader.key)
player_mind.active = TRUE
//if you want to add a fugitive with a special leader in the future, make this switch with the backstory
var/mob/living/carbon/human/S = gear_fugitive(leader, landing_turf, backstory)
var/obj/item/choice_beacon/augments/A = new(S)
S.put_in_hands(A)
new /obj/item/autosurgeon(landing_turf)
//security team gets called in after 10 minutes of prep to find the refugees
/datum/round_event/ghost_role/fugitives/proc/spawn_hunters()
var/backstory = pick("space cop", "russian", "bounty hunter")
var/datum/map_template/shuttle/ship
if(backstory == "space cop")
ship = new /datum/map_template/shuttle/hunter/space_cop
else if (backstory == "russian")
ship = new /datum/map_template/shuttle/hunter/russian
else
ship = new /datum/map_template/shuttle/hunter/bounty
var/x = rand(TRANSITIONEDGE,world.maxx - TRANSITIONEDGE - ship.width)
var/y = rand(TRANSITIONEDGE,world.maxy - TRANSITIONEDGE - ship.height)
var/z = SSmapping.empty_space.z_value
var/turf/T = locate(x,y,z)
if(!T)
CRASH("Fugitive Hunters (Created from fugitive event) found no turf to load in")
if(!ship.load(T))
CRASH("Loading [backstory] ship failed!")
priority_announce("Unidentified ship detected near the station.")
+99
View File
@@ -0,0 +1,99 @@
///Spawns a cargo pod containing a random cargo supply pack on a random area of the station
/datum/round_event_control/stray_cargo
name = "Stray Cargo Pod"
typepath = /datum/round_event/stray_cargo
weight = 20
max_occurrences = 4
earliest_start = 10 MINUTES
///Spawns a cargo pod containing a random cargo supply pack on a random area of the station
/datum/round_event/stray_cargo
var/area/impact_area ///Randomly picked area
var/list/possible_pack_types = list() ///List of possible supply packs dropped in the pod, if empty picks from the cargo list
var/static/list/stray_spawnable_supply_packs = list() ///List of default spawnable supply packs, filtered from the cargo list
/datum/round_event/stray_cargo/announce(fake)
priority_announce("Stray cargo pod detected on long-range scanners. Expected location of impact: [impact_area.name].", "Collision Alert")
/**
* Tries to find a valid area, throws an error if none are found
* Also randomizes the start timer
*/
/datum/round_event/stray_cargo/setup()
startWhen = rand(20, 40)
impact_area = find_event_area()
if(!impact_area)
CRASH("No valid areas for cargo pod found.")
var/list/turf_test = get_area_turfs(impact_area)
if(!turf_test.len)
CRASH("Stray Cargo Pod : No valid turfs found for [impact_area] - [impact_area.type]")
if(!stray_spawnable_supply_packs.len)
stray_spawnable_supply_packs = SSshuttle.supply_packs.Copy()
for(var/pack in stray_spawnable_supply_packs)
var/datum/supply_pack/pack_type = pack
if(initial(pack_type.special))
stray_spawnable_supply_packs -= pack
///Spawns a random supply pack, puts it in a pod, and spawns it on a random tile of the selected area
/datum/round_event/stray_cargo/start()
var/list/turf/valid_turfs = get_area_turfs(impact_area)
//Only target non-dense turfs to prevent wall-embedded pods
for(var/i in valid_turfs)
var/turf/T = i
if(T.density)
valid_turfs -= T
var/turf/LZ = pick(valid_turfs)
var/pack_type
if(possible_pack_types.len)
pack_type = pick(possible_pack_types)
else
pack_type = pick(stray_spawnable_supply_packs)
var/datum/supply_pack/SP = new pack_type
var/obj/structure/closet/crate/crate = SP.generate(null)
crate.locked = FALSE //Unlock secure crates
crate.update_icon()
var/obj/structure/closet/supplypod/pod = make_pod()
crate.forceMove(pod)
new /obj/effect/abstract/DPtarget(LZ, pod)
///Handles the creation of the pod, in case it needs to be modified beforehand
/datum/round_event/stray_cargo/proc/make_pod()
var/obj/structure/closet/supplypod/S = new
return S
///Picks an area that wouldn't risk critical damage if hit by a pod explosion
/datum/round_event/stray_cargo/proc/find_event_area()
var/static/list/allowed_areas
if(!allowed_areas)
///Places that shouldn't explode
var/list/safe_area_types = typecacheof(list(
/area/ai_monitored/turret_protected/ai,
/area/ai_monitored/turret_protected/ai_upload,
/area/engine,
/area/shuttle)
)
///Subtypes from the above that actually should explode.
var/list/unsafe_area_subtypes = typecacheof(list(/area/engine/break_room))
allowed_areas = make_associative(GLOB.the_station_areas) - safe_area_types + unsafe_area_subtypes
var/list/possible_areas = typecache_filter_list(GLOB.sortedAreas,allowed_areas)
if (length(possible_areas))
return pick(possible_areas)
///A rare variant that drops a crate containing syndicate uplink items
/datum/round_event_control/stray_cargo/syndicate
name = "Stray Syndicate Cargo Pod"
typepath = /datum/round_event/stray_cargo/syndicate
weight = 0
max_occurrences = 0
earliest_start = 30 MINUTES
/datum/round_event/stray_cargo/syndicate
possible_pack_types = list(/datum/supply_pack/misc/syndicate)
///Apply the syndicate pod skin
/datum/round_event/stray_cargo/syndicate/make_pod()
var/obj/structure/closet/supplypod/S = new
S.setStyle(STYLE_SYNDICATE)
return S
-46
View File
@@ -140,22 +140,6 @@
typepath = /datum/round_event/vent_clog/plasma_decon
max_occurrences = 0
/datum/round_event_control/vent_clog/female
name = "Clogged Vents; Girlcum"
typepath = /datum/round_event/vent_clog/female
max_occurrences = 0
/datum/round_event/vent_clog/female
reagentsAmount = 100
/datum/round_event_control/vent_clog/male
name = "Clogged Vents: Semen"
typepath = /datum/round_event/vent_clog/male
max_occurrences = 0
/datum/round_event/vent_clog/male
reagentsAmount = 100
/datum/round_event/vent_clog/beer/announce()
priority_announce("The scrubbers network is experiencing an unexpected surge of pressurized beer. Some ejection of contents may occur.", "Atmospherics alert")
@@ -171,36 +155,6 @@
foam.start()
CHECK_TICK
/datum/round_event/vent_clog/male/announce()
priority_announce("The scrubbers network is experiencing a backpressure surge. Some ejaculation of contents may occur.", "Atmospherics alert")
/datum/round_event/vent_clog/male/start()
for(var/obj/machinery/atmospherics/components/unary/vent in vents)
if(vent && vent.loc && !vent.welded)
var/datum/reagents/R = new/datum/reagents(1000)
R.my_atom = vent
R.add_reagent(/datum/reagent/consumable/semen, reagentsAmount)
var/datum/effect_system/foam_spread/foam = new
foam.set_up(200, get_turf(vent), R)
foam.start()
CHECK_TICK
/datum/round_event/vent_clog/female/announce()
priority_announce("The scrubbers network is experiencing a backpressure squirt. Some ejection of contents may occur.", "Atmospherics alert")
/datum/round_event/vent_clog/female/start()
for(var/obj/machinery/atmospherics/components/unary/vent in vents)
if(vent && vent.loc && !vent.welded)
var/datum/reagents/R = new/datum/reagents(1000)
R.my_atom = vent
R.add_reagent(/datum/reagent/consumable/femcum, reagentsAmount)
var/datum/effect_system/foam_spread/foam = new
foam.set_up(200, get_turf(vent), R)
foam.start()
CHECK_TICK
/datum/round_event/vent_clog/plasma_decon/announce()
priority_announce("We are deploying an experimental plasma decontamination system. Please stand away from the vents and do not breathe the smoke that comes out.", "Central Command Update")
+15
View File
@@ -0,0 +1,15 @@
/datum/round_event_control/wisdomcow
name = "Wisdom cow"
typepath = /datum/round_event/wisdomcow
max_occurrences = 1
weight = 20
/datum/round_event/wisdomcow/announce(fake)
priority_announce("A wise cow has been spotted in the area. Be sure to ask for her advice.", "Nanotrasen Cow Ranching Agency")
/datum/round_event/wisdomcow/start()
var/turf/targetloc = get_random_station_turf()
new /mob/living/simple_animal/cow/wisdom(targetloc)
var/datum/effect_system/smoke_spread/smoke = new
smoke.set_up(1, targetloc)
smoke.start()
+46
View File
@@ -0,0 +1,46 @@
/datum/round_event_control/wizard/embedpocalypse
name = "Make Everything Embeddable"
weight = 2
typepath = /datum/round_event/wizard/embedpocalypse
max_occurrences = 1
earliest_start = 0 MINUTES
/datum/round_event/wizard/embedpocalypse/start()
for(var/obj/item/I in world)
CHECK_TICK
if(!(I.flags_1 & INITIALIZED_1))
continue
if(!I.embedding || I.embedding == EMBED_HARMLESS)
I.embedding = EMBED_POINTY
I.updateEmbedding()
I.name = "pointy [I.name]"
GLOB.embedpocalypse = TRUE
GLOB.stickpocalypse = FALSE // embedpocalypse takes precedence over stickpocalypse
/datum/round_event_control/wizard/embedpocalypse/sticky
name = "Make Everything Sticky"
weight = 6
typepath = /datum/round_event/wizard/embedpocalypse/sticky
max_occurrences = 1
earliest_start = 0 MINUTES
/datum/round_event_control/wizard/embedpocalypse/sticky/canSpawnEvent(players_amt, gamemode)
if(GLOB.embedpocalypse)
return FALSE
/datum/round_event/wizard/embedpocalypse/sticky/start()
for(var/obj/item/I in world)
CHECK_TICK
if(!(I.flags_1 & INITIALIZED_1))
continue
if(!I.embedding)
I.embedding = EMBED_HARMLESS
I.updateEmbedding()
I.name = "sticky [I.name]"
GLOB.stickpocalypse = TRUE
-4
View File
@@ -1,7 +1,3 @@
/mob/living/carbon/proc/handle_dreams()
if(prob(10) && !dreaming)
dream()
/mob/living/carbon/proc/dream()
set waitfor = FALSE
var/list/dream_fragments = list()
-3
View File
@@ -6,7 +6,6 @@
/// get_random_food proc.
////////////////////////////////////////////////////////////////////////////////
#define STOP_SERVING_BREAKFAST (15 MINUTES)
/obj/item/reagent_containers/food
possible_transfer_amounts = list()
@@ -51,5 +50,3 @@
if((foodtype & BREAKFAST) && world.time - SSticker.round_start_time < STOP_SERVING_BREAKFAST)
SEND_SIGNAL(H, COMSIG_ADD_MOOD_EVENT, "breakfast", /datum/mood_event/breakfast)
last_check_time = world.time
#undef STOP_SERVING_BREAKFAST
+4 -4
View File
@@ -303,12 +303,12 @@ All foods are distributed among various categories. Use common sense.
var/obj/item/result
if(cooked_type)
result = new cooked_type(T)
//if the result is food, set its food quality to the original food item's quality
if(isfood(result))
var/obj/item/reagent_containers/food/food_output = result
food_output.adjust_food_quality(food_quality + M.quality_increase)
if(istype(M))
initialize_cooked_food(result, M.efficiency)
//if the result is food, set its food quality to the original food item's quality
if(isfood(result))
var/obj/item/reagent_containers/food/food_output = result
food_output.adjust_food_quality(food_quality + M.quality_increase)
else
initialize_cooked_food(result, 1)
SSblackbox.record_feedback("tally", "food_made", 1, result.type)
@@ -1,6 +1,7 @@
/obj/item/reagent_containers/food/snacks/meat
var/subjectname = ""
var/subjectjob = null
custom_materials = list(/datum/material/meat = MINERAL_MATERIAL_AMOUNT * 4)
/obj/item/reagent_containers/food/snacks/meat/slab
name = "meat"
@@ -315,6 +316,15 @@
slice_path = /obj/item/reagent_containers/food/snacks/meat/rawcutlet/gondola
foodtype = RAW | MEAT
/obj/item/reagent_containers/food/snacks/meat/slab/wisdomcow
name = "wisdom cow meat"
desc = "The meat from the legendary creature known as the wisdom cow. You monster."
list_reagents = list(/datum/reagent/consumable/nutriment = 3, /datum/reagent/medicine/liquid_wisdom = 5)
tastes = list("meat" = 1, "wisdom" = 5)
filling_color = "#18e3ca"
cooked_type = /obj/item/reagent_containers/food/snacks/meat/steak/wisdomcow
slice_path = /obj/item/reagent_containers/food/snacks/meat/rawcutlet/wisdomcow
////////////////////////////////////// MEAT STEAKS ///////////////////////////////////////////////////////////
@@ -374,6 +384,10 @@
name = "gondola steak"
tastes = list("meat" = 1, "tranquility" = 1)
/obj/item/reagent_containers/food/snacks/meat/steak/wisdomcow
name = "wisdom cow steak"
tastes = list("meat" = 1, "wisdom" = 5)
//////////////////////////////// MEAT CUTLETS ///////////////////////////////////////////////////////
//Raw cutlets
@@ -441,6 +455,11 @@
cooked_type = /obj/item/reagent_containers/food/snacks/meat/cutlet/gondola
tastes = list("meat" = 1, "tranquility" = 1)
/obj/item/reagent_containers/food/snacks/meat/rawcutlet/wisdomcow
name = "raw wisdom cow cutlet"
cooked_type = /obj/item/reagent_containers/food/snacks/meat/cutlet/wisdomcow
tastes = list("meat" = 1, "wisdom" = 5)
//Cooked cutlets
/obj/item/reagent_containers/food/snacks/meat/cutlet
@@ -488,3 +507,7 @@
/obj/item/reagent_containers/food/snacks/meat/cutlet/chicken
name = "chicken cutlet"
tastes = list("chicken" = 1)
/obj/item/reagent_containers/food/snacks/meat/cutlet/wisdomcow
name = "wisdom cow cutlet"
tastes = list("meat" = 1, "wisdom" = 5)
@@ -10,6 +10,17 @@
tastes = list("crust" = 1, "tomato" = 1, "cheese" = 1)
foodtype = GRAIN | DAIRY | VEGETABLES
/obj/item/reagent_containers/food/snacks/pizzaslice/attackby(obj/item/I, mob/user, params)
if(istype(I, /obj/item/kitchen/rollingpin))
if(!isturf(loc))
to_chat(user, "<span class='warning'>You need to put [src] on a surface to roll it out!</span>")
return
new /obj/item/stack/sheet/pizza(loc)
to_chat(user, "<span class='notice'>You smoosh [src] into a cheesy sheet.</span>")
qdel(src)
return
return ..()
/obj/item/reagent_containers/food/snacks/pizzaslice
icon = 'icons/obj/food/pizzaspaghetti.dmi'
list_reagents = list(/datum/reagent/consumable/nutriment = 5)
@@ -1,5 +1,5 @@
#define STORAGE_CAPACITY 30
#define LIQUID_CAPACIY 200
#define LIQUID_CAPACITY 200
#define MIXER_CAPACITY 100
/obj/machinery/food_cart
@@ -19,7 +19,7 @@
/obj/machinery/food_cart/Initialize()
. = ..()
create_reagents(LIQUID_CAPACIY, OPENCONTAINER | NO_REACT)
create_reagents(LIQUID_CAPACITY, OPENCONTAINER | NO_REACT)
mixer = new /obj/item/reagent_containers(src, MIXER_CAPACITY)
mixer.name = "Mixer"
@@ -60,6 +60,9 @@
return food_stored >= STORAGE_CAPACITY
/obj/machinery/food_cart/attackby(obj/item/O, mob/user, params)
if(O.tool_behaviour == TOOL_WRENCH)
default_unfasten_wrench(user, O, 0)
return TRUE
if(istype(O, /obj/item/reagent_containers/food/drinks/drinkingglass))
var/obj/item/reagent_containers/food/drinks/drinkingglass/DG = O
if(!DG.reagents.total_volume) //glass is empty
@@ -106,7 +109,7 @@
return
if(href_list["disposeI"])
reagents.del_reagent(href_list["disposeI"])
reagents.del_reagent(text2path(href_list["disposeI"]))
if(href_list["dispense"])
if(stored_food[href_list["dispense"]]-- <= 0)
@@ -116,9 +119,13 @@
if(sanitize(O.name) == href_list["dispense"])
O.forceMove(drop_location())
break
log_combat(usr, src, "dispensed [O] from", null, "with [stored_food[href_list["dispense"]]] remaining")
if(href_list["portion"])
portion = clamp(input("How much drink do you want to dispense per glass?") as num, 0, 50)
portion = clamp(input("How much drink do you want to dispense per glass?") as num|null, 0, 50)
if (isnull(portion))
return
if(href_list["pour"] || href_list["m_pour"])
if(glasses-- <= 0)
@@ -127,16 +134,16 @@
else
var/obj/item/reagent_containers/food/drinks/drinkingglass/DG = new(loc)
if(href_list["pour"])
reagents.trans_id_to(DG, href_list["pour"], portion)
reagents.trans_id_to(DG, text2path(href_list["pour"]), portion)
if(href_list["m_pour"])
mixer.reagents.trans_id_to(DG, href_list["m_pour"], portion)
mixer.reagents.trans_id_to(DG, text2path(href_list["m_pour"]), portion)
if(href_list["mix"])
if(reagents.trans_id_to(mixer, href_list["mix"], portion) == 0)
if(reagents.trans_id_to(mixer, text2path(href_list["mix"]), portion) == 0)
to_chat(usr, "<span class='warning'>[mixer] is full!</span>")
if(href_list["transfer"])
if(mixer.reagents.trans_id_to(src, href_list["transfer"], portion) == 0)
if(mixer.reagents.trans_id_to(src, text2path(href_list["transfer"]), portion) == 0)
to_chat(usr, "<span class='warning'>[src] is full!</span>")
updateDialog()
@@ -152,5 +159,5 @@
qdel(src)
#undef STORAGE_CAPACITY
#undef LIQUID_CAPACIY
#undef LIQUID_CAPACITY
#undef MIXER_CAPACITY
@@ -463,7 +463,7 @@
return TRUE
if(!O.reagents || !O.reagents.reagent_list.len) // other empty containers not accepted
return FALSE
if(istype(O, /obj/item/reagent_containers/syringe) || istype(O, /obj/item/reagent_containers/glass/bottle) || istype(O, /obj/item/reagent_containers/glass/beaker) || istype(O, /obj/item/reagent_containers/spray) || istype(O, /obj/item/reagent_containers/medspray))
if(istype(O, /obj/item/reagent_containers/syringe) || istype(O, /obj/item/reagent_containers/glass/bottle) || istype(O, /obj/item/reagent_containers/glass/beaker) || istype(O, /obj/item/reagent_containers/spray) || istype(O, /obj/item/reagent_containers/medspray) || istype(O, /obj/item/reagent_containers/chem_pack))
return TRUE
return FALSE
@@ -88,7 +88,7 @@
/obj/item/t_scanner = 5,
/obj/item/airlock_painter = 1,
/obj/item/stack/cable_coil = 6,
/obj/item/stack/medical/bruise_pack = 1,
/obj/item/stack/medical/suture = 1,
/obj/item/stack/rods = 3,
/obj/item/stack/sheet/cardboard = 2,
/obj/item/stack/sheet/metal = 1,
+3 -2
View File
@@ -56,8 +56,9 @@
cached_z = z
poof()
/mob/living/simple_animal/jacq/Life()
..()
/mob/living/simple_animal/jacq/BiologicalLife(seconds, times_fired)
if(!(. = ..()))
return
if(!ckey)
if((last_poof+3 MINUTES) < world.realtime)
poof()
+1 -1
View File
@@ -195,7 +195,7 @@
/obj/item/reagent_containers/food/snacks/grown/firelemon/ex_act(severity)
qdel(src) //Ensuring that it's deleted by its own explosion
/obj/item/reagent_containers/food/snacks/grown/firelemon/proc/prime()
/obj/item/reagent_containers/food/snacks/grown/firelemon/proc/prime(mob/living/lanced_by)
switch(seed.potency) //Combustible lemons are alot like IEDs, lots of flame, very little bang.
if(0 to 30)
update_mob()
+1 -1
View File
@@ -223,7 +223,7 @@
/obj/item/reagent_containers/food/snacks/grown/cherry_bomb/ex_act(severity)
qdel(src) //Ensuring that it's deleted by its own explosion. Also prevents mass chain reaction with piles of cherry bombs
/obj/item/reagent_containers/food/snacks/grown/cherry_bomb/proc/prime()
/obj/item/reagent_containers/food/snacks/grown/cherry_bomb/proc/prime(mob/living/lanced_by)
icon_state = "cherry_bomb_lit"
playsound(src, 'sound/effects/fuse.ogg', seed.potency, 0)
addtimer(CALLBACK(src, /obj/item/reagent_containers/food/snacks/grown/cherry_bomb/proc/detonate), rand(50, 100))
@@ -283,10 +283,8 @@
/obj/item/integrated_circuit/arithmetic/square_root/do_work()
var/result = 0
for(var/k in 2 to inputs.len)
var/I = get_pin_data(IC_INPUT, k)
if(isnum(I))
result += sqrt(I)
var/I = get_pin_data(IC_INPUT, 1)
result = sqrt(I)
set_pin_data(IC_OUTPUT, 1, result)
push_data()
@@ -78,7 +78,7 @@
for(var/i in 1 to length(harvest_output))
harvest_output[i] = WEAKREF(harvest_output[i])
if(harvest_output.len)
if(length(harvest_output))
set_pin_data(IC_OUTPUT, 1, harvest_output)
push_data()
if(1)
@@ -81,7 +81,7 @@
to_chat(user, "<span class='notice'>There's no weapon to remove from the mechanism.</span>")
/obj/item/integrated_circuit/weaponized/weapon_firing/do_work()
if(!assembly || !installed_gun)
if(!assembly || !installed_gun || !installed_gun.can_shoot())
return
if(isliving(assembly.loc))
var/mob/living/L = assembly.loc
+89 -57
View File
@@ -1,21 +1,27 @@
/datum/minimap
var/name
var/name = "minimap"
var/icon/overlay_icon
// The map icons
var/icon/map_icon
var/icon/meta_icon
var/icon/overlay_icon
var/list/color_area_names = list()
var/minx
var/maxx
var/miny
var/maxy
var/z_level
var/id = 0
var/static/next_id = 0
/datum/minimap/New(z, x1 = 1, y1 = 1, x2 = world.maxx, y2 = world.maxy, name)
var/z_level
var/id = ""
/datum/minimap/New(z, x1 = 1, y1 = 1, x2 = world.maxx, y2 = world.maxy, name = "minimap")
if(!z)
CRASH("ERROR: new minimap requested without z level") //CRASH to halt the operatio
src.name = name
id = ++next_id
z_level = z
id = "[md5("[z_level]" + src.name + REF(src))]" //use it's own md5 as a special identifier
var/crop_x1 = x2
var/crop_x2 = x1
@@ -25,10 +31,11 @@
// do the generating
map_icon = new('html/blank.png')
meta_icon = new('html/blank.png')
map_icon.Scale(x2-x1+1, y2-y1+1) // arrays start at 1
meta_icon.Scale(x2-x1+1, y2-y1+1)
map_icon.Scale(x2 - x1 + 1, y2 - y1 + 1) // arrays start at 1
meta_icon.Scale(x2 - x1 + 1, y2 - y1 + 1)
var/list/area_to_color = list()
for(var/turf/T in block(locate(x1,y1,z),locate(x2,y2,z)))
for(var/turf/T in block(locate(x1, y1, z_level), locate(x2, y2, z_level)))
var/area/A = T.loc
var/img_x = T.x - x1 + 1 // arrays start at 1
var/img_y = T.y - y1 + 1
@@ -37,21 +44,26 @@
crop_x2 = max(crop_x2, T.x)
crop_y1 = min(crop_y1, T.y)
crop_y2 = max(crop_y2, T.y)
var/meta_color = area_to_color[A]
if(!meta_color)
meta_color = rgb(rand(0,255),rand(0,255),rand(0,255)) // technically conflicts could happen but it's like very unlikely and it's not that big of a deal if one happens
meta_color = rgb(rand(0, 255), rand(0, 255), rand(0, 255)) // technically conflicts could happen but it's like very unlikely and it's not that big of a deal if one happens
area_to_color[A] = meta_color
color_area_names[meta_color] = A.name
meta_icon.DrawBox(meta_color, img_x, img_y)
if(istype(T, /turf/closed/wall))
map_icon.DrawBox("#000000", img_x, img_y)
else if(!istype(A, /area/space))
var/color = A.minimap_color || "#FF00FF"
if(locate(/obj/machinery/power/solar) in T)
color = "#02026a"
if((locate(/obj/effect/spawner/structure/window) in T) || (locate(/obj/structure/grille) in T))
color = BlendRGB(color, "#000000", 0.5)
map_icon.DrawBox(color, img_x, img_y)
map_icon.Crop(crop_x1, crop_y1, crop_x2, crop_y2)
meta_icon.Crop(crop_x1, crop_y1, crop_x2, crop_y2)
minx = crop_x1
@@ -60,14 +72,17 @@
maxy = crop_y2
overlay_icon = new(map_icon)
overlay_icon.Scale(16, 16)
/datum/minimap/proc/send(mob/user)
//we're done baking, now we ship it.
register_asset("minimap-[id].png", map_icon)
register_asset("minimap-[id]-meta.png", meta_icon)
send_asset_list(user, list("minimap-[id].png" = map_icon, "minimap-[id]-meta.png" = meta_icon), verify=FALSE)
/datum/minimap/proc/send(mob/user)
if(!id)
CRASH("ERROR: send called, but the minimap id is null/missing. ID: [id]")
send_asset_list(user, list("minimap-[id].png" = map_icon, "minimap-[id]-meta.png" = meta_icon))
/datum/minimap_group
var/list/minimaps
var/list/minimaps = list()
var/static/next_id = 0
var/id
var/name
@@ -75,46 +90,62 @@
/datum/minimap_group/New(list/maps, name)
id = ++next_id
src.name = name
minimaps = maps || list()
if(maps)
minimaps = maps
/datum/minimap_group/proc/show(mob/user)
if(!length(minimaps))
to_chat(user, "<span class='boldwarning'>ERROR: Attempted to access an empty datum/minimap_group. This should probably not happen.</span>")
return
var/list/datas = list()
var/list/info = list()
var/datum/minimap/first_map = minimaps[1]
for(var/i in 1 to length(minimaps))
for(var/i in 1 to length(minimaps))// OLD: for(var/i in 1 to length(minimaps))
var/datum/minimap/M = minimaps[i]
M.send(user)
info += "<img src='minimap-[M.id].png' id='map-[i]'><img src='minimap-[M.id]-meta.png' style='display: none' id='map-[i]-meta'><div id='label-[i]'></div>"
info += {"
<div class="block">
<div> <!-- The div is in here to fit it both in the block div -->
<img id='map-[i]' src='minimap-[M.id].png' />
<img id='map-[i]-meta' src='minimap-[M.id]-meta.png' style='display: none' />
</div>
<div class="statusDisplay" id='label-[i]'></div>
</div>
"}
datas += json_encode(M.color_area_names);
info = info.Join()
var/html = {"
<!DOCTYPE html>
<HTML>
<HEAD>
<meta http-equiv='X-UA-Compatible' content='IE=edge'>
<meta http-equiv='Content-Type' content='text/html; charset=UTF-8'>
<script>
function hexify(num) {
if(!num) num = 0;
num = num.toString(16);
if(num.length == 1) num = "0" + num;
return num;
}
window.onload = function() {
var datas = \[[jointext(datas, ",")]]
if(window.HTMLCanvasElement) {
for(var i = 0; i < [minimaps.len]; i++) {
(function() {
info = info.Join()
//this is bad. Too bad!
var/headerJS = {"
<script>
function hexify(num) {
if(!num){
num = 0;
}
num = num.toString(16);
if(num.length == 1){
num = "0" + num;
}
return num;
}
window.onload = function() {
var datas = \[[jointext(datas, ",")]]
if(!window.HTMLCanvasElement){
//something has gone horribly wrong!
return false
}
for(var i = 0; i < [length(minimaps)]; i++){
//the fuck is this wrapped?
var data = datas\[i];
var img = document.getElementById("map-" + (i+1));
if(!img) return;
var img = document.getElementById("map-" + (i + 1));
if(!img){
return; //if it does not exist, it means it's done!
}
var canvas = document.createElement("canvas");
canvas.width = img.width * 2;
canvas.height = img.height * 2;
var ctx = canvas.getContext('2d');
ctx.msImageSmoothingEnabled = false;
ctx.drawImage(img, 0, 0, canvas.width, canvas.height);
@@ -123,9 +154,10 @@ window.onload = function() {
ctx.canvas.width = img.width;
ctx.canvas.height = img.height;
ctx.drawImage(document.getElementById("map-" + (i+1) + "-meta"), 0, 0);
var imagedata = ctx.getImageData(0, 0, img.width, img.height);
var label = document.getElementById("label-" + (i+1));
canvas.onmousemove = function(e) {
canvas.onmousemove = function(e){
var rect = canvas.getBoundingClientRect();
var x = Math.floor(e.offsetX * img.width / rect.width);
var y = Math.floor(e.offsetY * img.height / rect.height);
@@ -134,23 +166,23 @@ window.onload = function() {
label.textContent = data\[color];
canvas.title = data\[color];
}
canvas.onmouseout = function(e) {
label.textContent = "";
canvas.onmouseout = function(e){
canvas.title = "";
}
})();
}
}
}
}
</script>
<STYLE>
img, canvas {
width: 100%
}
</STYLE>
<TITLE>[name]</TITLE>
</HEAD>
<BODY>[info]</BODY>
</HTML>"}
</script>
<style>
img, canvas {
width: 100%;
background-color: white;
}
</style>
"}
user << browse(html, "window=minimap_[id];size=768x[round(768 / first_map.map_icon.Width() * first_map.map_icon.Height() + 50)]")
var/datum/browser/popup = new(user, "minimap_[id]", name, 500, 700)
popup.add_head_content(headerJS) //set the head
popup.set_content(info)
var/datum/minimap/MICO = minimaps[1]
popup.set_title_image(MICO.overlay_icon)
popup.open(FALSE)
@@ -111,9 +111,6 @@
go_inert()
return ..()
/obj/item/organ/regenerative_core/prepare_eat()
return null
/*************************Legion core********************/
/obj/item/organ/regenerative_core/legion
desc = "A strange rock that crackles with power. It can be used to heal completely, but it will rapidly decay into uselessness."
@@ -11,7 +11,7 @@
desc = "It's watching you suspiciously."
/obj/structure/closet/crate/necropolis/tendril/PopulateContents()
var/loot = rand(1,28)
var/loot = rand(1,29)
switch(loot)
if(1)
new /obj/item/shared_storage/red(src)
@@ -77,6 +77,11 @@
new /obj/item/bedsheet/cult(src)
if(28)
new /obj/item/clothing/neck/necklace/memento_mori(src)
if(29)
if(prob(50))
new /obj/item/malf_upgrade
else
new /obj/item/disk/tech_disk/illegal
//KA modkit design discs
/obj/item/disk/design_disk/modkit_disc
@@ -487,7 +492,7 @@
setDir(user.dir)
user.forceMove(src)
user.notransform = TRUE
user.mob_transforming = TRUE
user.status_flags |= GODMODE
can_destroy = FALSE
@@ -496,7 +501,7 @@
/obj/effect/immortality_talisman/proc/unvanish(mob/user)
user.status_flags &= ~GODMODE
user.notransform = FALSE
user.mob_transforming = FALSE
user.forceMove(get_turf(src))
user.visible_message("<span class='danger'>[user] pops back into reality!</span>")
-1
View File
@@ -17,7 +17,6 @@
var/points = 0 //How many points this ore gets you from the ore redemption machine
var/refined_type = null //What this ore defaults to being refined into
novariants = TRUE // Ore stacks handle their icon updates themselves to keep the illusion that there's more going
mats_per_stack = MINERAL_MATERIAL_AMOUNT
var/list/stack_overlays
/obj/item/stack/ore/update_overlays()
+3 -3
View File
@@ -68,7 +68,7 @@ INITIALIZE_IMMEDIATE(/mob/dead)
set category = "OOC"
set name = "Server Hop!"
set desc= "Jump to the other server"
if(notransform)
if(mob_transforming)
return
var/list/csa = CONFIG_GET(keyed_list/cross_server)
var/pick
@@ -93,9 +93,9 @@ INITIALIZE_IMMEDIATE(/mob/dead)
to_chat(C, "<span class='notice'>Sending you to [pick].</span>")
new /obj/screen/splash(C)
notransform = TRUE
mob_transforming = TRUE
sleep(29) //let the animation play
notransform = FALSE
mob_transforming = FALSE
if(!C)
return
+4 -2
View File
@@ -94,7 +94,9 @@
//We want an accurate reading of .len
listclearnulls(BP.embedded_objects)
temp_bleed += 0.5 * BP.embedded_objects.len
for(var/obj/item/embeddies in BP.embedded_objects)
if(!embeddies.isEmbedHarmless())
temp_bleed += 0.5
if(brutedamage >= 20)
temp_bleed += (brutedamage * 0.013)
@@ -186,7 +188,7 @@
blood_data["viruses"] += D.Copy()
blood_data["blood_DNA"] = dna.unique_enzymes
blood_data["bloodcolor"] = bloodtype_to_color(dna.blood_type)
blood_data["bloodcolor"] = dna.species.exotic_blood_color
if(disease_resistances && disease_resistances.len)
blood_data["resistances"] = disease_resistances.Copy()
var/list/temp_chem = list()
+3 -3
View File
@@ -37,10 +37,10 @@
C.put_in_hands(B1)
C.put_in_hands(B2)
C.regenerate_icons()
src.notransform = TRUE
src.mob_transforming = TRUE
spawn(0)
bloodpool_sink(B)
src.notransform = FALSE
src.mob_transforming = FALSE
return 1
/mob/living/proc/bloodpool_sink(obj/effect/decal/cleanable/B)
@@ -155,7 +155,7 @@
addtimer(CALLBACK(src, /atom/.proc/remove_atom_colour, TEMPORARY_COLOUR_PRIORITY, newcolor), 6 SECONDS)
/mob/living/proc/phasein(obj/effect/decal/cleanable/B)
if(src.notransform)
if(src.mob_transforming)
to_chat(src, "<span class='warning'>Finish eating first!</span>")
return 0
B.visible_message("<span class='warning'>[B] starts to bubble...</span>")
@@ -76,9 +76,6 @@
REMOVE_SKILL_MODIFIER_BODY(/datum/skill_modifier/heavy_brain_damage, null, C)
C.update_hair()
/obj/item/organ/brain/prepare_eat()
return // Too important to eat.
/obj/item/organ/brain/proc/transfer_identity(mob/living/L)
name = "[L.name]'s brain"
if(brainmob)
+2 -6
View File
@@ -1,11 +1,7 @@
/mob/living/brain/Life()
set invisibility = 0
if (notransform)
/mob/living/brain/BiologicalLife(seconds, times_fired)
if(!(. = ..()))
return
if(!loc)
return
. = ..()
handle_emp_damage()
/mob/living/brain/update_stat()
@@ -8,9 +8,6 @@
/mob/living/carbon/alien/hitby(atom/movable/AM, skipcatch, hitpush, blocked, datum/thrownthing/throwingdatum)
return ..(AM, skipcatch = TRUE, hitpush = FALSE)
/mob/living/carbon/alien/can_embed(obj/item/I)
return FALSE
/*Code for aliens attacking aliens. Because aliens act on a hivemind, I don't see them as very aggressive with each other.
As such, they can either help or harm other aliens. Help works like the human help command while harm is a simple nibble.
In all, this is a lot like the monkey code. /N
@@ -54,6 +51,8 @@ In all, this is a lot like the monkey code. /N
return
switch(M.a_intent)
if(INTENT_HELP)
if(M == src && check_self_for_injuries())
return
help_shake_act(M)
if(INTENT_GRAB)
grabbedby(M)
@@ -1,14 +1,10 @@
/mob/living/carbon/alien/larva/Life()
set invisibility = 0
if (notransform)
/mob/living/carbon/alien/larva/BiologicalLife(seconds, times_fired)
if(!(. = ..()))
return
if(..()) //not dead
// GROW!
if(amount_grown < max_grown)
amount_grown++
update_icons()
// GROW!
if(amount_grown < max_grown)
amount_grown++
update_icons()
/mob/living/carbon/alien/larva/update_stat()
+3 -2
View File
@@ -1,6 +1,7 @@
/mob/living/carbon/alien/Life()
/mob/living/carbon/alien/BiologicalLife(seconds, times_fired)
if(!(. = ..()))
return
findQueen()
return..()
/mob/living/carbon/alien/check_breath(datum/gas_mixture/breath)
if(status_flags & GODMODE)
+3 -12
View File
@@ -1,7 +1,8 @@
/obj/item/organ/alien
icon_state = "xgibmid2"
food_reagents = list(/datum/reagent/consumable/nutriment = 5, /datum/reagent/toxin/acid = 10)
var/list/alien_powers = list()
organ_flags = ORGAN_NO_SPOIL
organ_flags = ORGAN_NO_SPOIL|ORGAN_EDIBLE
/obj/item/organ/alien/Initialize()
. = ..()
@@ -26,12 +27,6 @@
owner.RemoveAbility(P)
..()
/obj/item/organ/alien/prepare_eat()
var/obj/S = ..()
S.reagents.add_reagent(/datum/reagent/toxin/acid, 10)
return S
/obj/item/organ/alien/plasmavessel
name = "plasma vessel"
icon_state = "plasma"
@@ -39,17 +34,13 @@
zone = BODY_ZONE_CHEST
slot = "plasmavessel"
alien_powers = list(/obj/effect/proc_holder/alien/plant, /obj/effect/proc_holder/alien/transfer)
food_reagents = list(/datum/reagent/consumable/nutriment = 5, /datum/reagent/toxin/plasma = 10)
var/storedPlasma = 100
var/max_plasma = 250
var/heal_rate = 5
var/plasma_rate = 10
/obj/item/organ/alien/plasmavessel/prepare_eat()
var/obj/S = ..()
S.reagents.add_reagent(/datum/reagent/toxin/plasma, storedPlasma/10)
return S
/obj/item/organ/alien/plasmavessel/large
name = "large plasma vessel"
icon_state = "plasma_large"
@@ -4,6 +4,7 @@
name = "alien embryo"
icon = 'icons/mob/alien.dmi'
icon_state = "larva0_dead"
food_reagents = list(/datum/reagent/consumable/nutriment = 5, /datum/reagent/toxin/acid = 10)
var/stage = 0
var/bursting = FALSE
@@ -16,11 +17,6 @@
if(prob(10))
AttemptGrow(0)
/obj/item/organ/body_egg/alien_embryo/prepare_eat()
var/obj/S = ..()
S.reagents.add_reagent(/datum/reagent/toxin/acid, 10)
return S
/obj/item/organ/body_egg/alien_embryo/on_life()
. = ..()
if(!owner)
@@ -92,7 +88,7 @@
ghost.transfer_ckey(new_xeno, FALSE)
SEND_SOUND(new_xeno, sound('sound/voice/hiss5.ogg',0,0,0,100)) //To get the player's attention
new_xeno.Paralyze(6)
new_xeno.notransform = TRUE
new_xeno.mob_transforming = TRUE
new_xeno.invisibility = INVISIBILITY_MAXIMUM
sleep(6)
@@ -102,7 +98,7 @@
if(new_xeno)
new_xeno.SetParalyzed(0)
new_xeno.notransform = FALSE
new_xeno.mob_transforming = FALSE
new_xeno.invisibility = 0
var/mob/living/carbon/old_owner = owner
+10 -2
View File
@@ -247,7 +247,7 @@
/mob/living/carbon/Topic(href, href_list)
..()
//strip panel
if(usr.canUseTopic(src, BE_CLOSE, NO_DEXTERY))
if(usr.canUseTopic(src, BE_CLOSE))
if(href_list["internal"] && !HAS_TRAIT(src, TRAIT_NO_INTERNALS))
var/slot = text2num(href_list["internal"])
var/obj/item/ITEM = get_item_by_slot(slot)
@@ -267,7 +267,15 @@
visible_message("<span class='danger'>[usr] [internal ? "opens" : "closes"] the valve on [src]'s [ITEM.name].</span>", \
"<span class='userdanger'>[usr] [internal ? "opens" : "closes"] the valve on your [ITEM.name].</span>", \
target = usr, target_message = "<span class='danger'>You [internal ? "opens" : "closes"] the valve on [src]'s [ITEM.name].</span>")
if(href_list["embedded_object"] && usr.canUseTopic(src, BE_CLOSE))
var/obj/item/bodypart/L = locate(href_list["embedded_limb"]) in bodyparts
if(!L)
return
var/obj/item/I = locate(href_list["embedded_object"]) in L.embedded_objects
if(!I || I.loc != src) //no item, no limb, or item is not in limb or in the person anymore
return
SEND_SIGNAL(src, COMSIG_CARBON_EMBED_RIP, I, L)
return
/mob/living/carbon/fall(forced)
loc.handle_fall(src, forced)//it's loc so it doesn't call the mob's handle_fall which does nothing
@@ -65,17 +65,6 @@
throw_mode_off()
return TRUE
/mob/living/carbon/embed_item(obj/item/I)
throw_alert("embeddedobject", /obj/screen/alert/embeddedobject)
var/obj/item/bodypart/L = pick(bodyparts)
L.embedded_objects |= I
I.add_mob_blood(src)//it embedded itself in you, of course it's bloody!
I.forceMove(src)
I.embedded()
L.receive_damage(I.w_class*I.embedding.embedded_impact_pain_multiplier)
visible_message("<span class='danger'>[I] embeds itself in [src]'s [L.name]!</span>","<span class='userdanger'>[I] embeds itself in your [L.name]!</span>")
SEND_SIGNAL(src, COMSIG_ADD_MOOD_EVENT, "embedded", /datum/mood_event/embedded)
/mob/living/carbon/attacked_by(obj/item/I, mob/living/user, attackchain_flags = NONE, damage_multiplier = 1)
var/totitemdamage = pre_attacked_by(I, user) * damage_multiplier
var/impacting_zone = (user == src)? check_zone(user.zone_selected) : ran_zone(user.zone_selected)
@@ -274,6 +263,9 @@
to_chat(M, "<span class='warning'>You can't put [p_them()] out with just your bare hands!</span>")
return
if(M == src && check_self_for_injuries())
return
if(health >= 0 && !(HAS_TRAIT(src, TRAIT_FAKEDEATH)))
var/friendly_check = FALSE
if(mob_run_block(M, 0, M.name, ATTACK_TYPE_UNARMED, 0, null, null, null))
@@ -341,6 +333,26 @@
update_mobility()
playsound(loc, 'sound/weapons/thudswoosh.ogg', 50, 1, -1)
/// Check ourselves to see if we've got any shrapnel, return true if we do. This is a much simpler version of what humans do, we only indicate we're checking ourselves if there's actually shrapnel
/mob/living/carbon/proc/check_self_for_injuries()
if(stat == DEAD || stat == UNCONSCIOUS)
return
var/embeds = FALSE
for(var/X in bodyparts)
var/obj/item/bodypart/LB = X
for(var/obj/item/I in LB.embedded_objects)
if(!embeds)
embeds = TRUE
// this way, we only visibly try to examine ourselves if we have something embedded, otherwise we'll still hug ourselves :)
visible_message("<span class='notice'>[src] examines [p_them()]self.</span>", \
"<span class='notice'>You check yourself for shrapnel.</span>")
if(I.isEmbedHarmless())
to_chat(src, "\t <a href='?src=[REF(src)];embedded_object=[REF(I)];embedded_limb=[REF(LB)]' class='warning'>There is \a [I] stuck to your [LB.name]!</a>")
else
to_chat(src, "\t <a href='?src=[REF(src)];embedded_object=[REF(I)];embedded_limb=[REF(LB)]' class='warning'>There is \a [I] embedded in your [LB.name]!</a>")
return embeds
/mob/living/carbon/flash_act(intensity = 1, override_blindness_check = 0, affect_silicon = 0, visual = 0)
. = ..()
+10 -9
View File
@@ -1,20 +1,21 @@
/mob/living/carbon/apply_damage(damage, damagetype = BRUTE, def_zone = null, blocked = FALSE, forced = FALSE)
/mob/living/carbon/apply_damage(damage, damagetype = BRUTE, def_zone = null, blocked = FALSE, forced = FALSE, spread_damage = FALSE)
SEND_SIGNAL(src, COMSIG_MOB_APPLY_DAMGE, damage, damagetype, def_zone)
var/hit_percent = (100-blocked)/100
if(!forced && hit_percent <= 0)
return 0
var/obj/item/bodypart/BP = null
if(isbodypart(def_zone)) //we specified a bodypart object
BP = def_zone
else
if(!def_zone)
def_zone = ran_zone(def_zone)
BP = get_bodypart(check_zone(def_zone))
if(!BP)
BP = bodyparts[1]
if(!spread_damage)
if(isbodypart(def_zone)) //we specified a bodypart object
BP = def_zone
else
if(!def_zone)
def_zone = ran_zone(def_zone)
BP = get_bodypart(check_zone(def_zone))
if(!BP)
BP = bodyparts[1]
var/damage_amount = forced ? damage : damage * hit_percent
switch(damagetype)
+25 -4
View File
@@ -31,14 +31,35 @@
else if(get_bodypart(BODY_ZONE_HEAD))
. += "<span class='deadsay'>It appears that [t_his] brain is missing...</span>"
var/list/missing = get_missing_limbs()
var/list/msg = list("<span class='warning'>")
var/list/missing = list(BODY_ZONE_HEAD, BODY_ZONE_CHEST, BODY_ZONE_R_ARM, BODY_ZONE_L_ARM, BODY_ZONE_R_LEG, BODY_ZONE_L_LEG)
var/list/disabled = list()
for(var/X in bodyparts)
var/obj/item/bodypart/BP = X
if(BP.disabled)
disabled += BP
missing -= BP.body_zone
for(var/obj/item/I in BP.embedded_objects)
if(I.isEmbedHarmless())
msg += "<B>[t_He] [t_has] \a [icon2html(I, user)] [I] stuck to [t_his] [BP.name]!</B>\n"
else
msg += "<B>[t_He] [t_has] \a [icon2html(I, user)] [I] embedded in [t_his] [BP.name]!</B>\n"
for(var/X in disabled)
var/obj/item/bodypart/BP = X
var/damage_text
if(!(BP.get_damage(include_stamina = FALSE) >= BP.max_damage)) //Stamina is disabling the limb
damage_text = "limp and lifeless"
else
damage_text = (BP.brute_dam >= BP.burn_dam) ? BP.heavy_brute_msg : BP.heavy_burn_msg
msg += "<B>[capitalize(t_his)] [BP.name] is [damage_text]!</B>\n"
for(var/t in missing)
if(t==BODY_ZONE_HEAD)
. += "<span class='deadsay'><B>[t_His] [parse_zone(t)] is missing!</B></span>"
msg += "<span class='deadsay'><B>[t_His] [parse_zone(t)] is missing!</B></span>\n"
continue
. += "<span class='warning'><B>[t_His] [parse_zone(t)] is missing!</B></span>"
msg += "<span class='warning'><B>[t_His] [parse_zone(t)] is missing!</B></span>\n"
var/list/msg = list()
var/temp = getBruteLoss()
if(!(user == src && src.hal_screwyhud == SCREWYHUD_HEALTHY)) //fake healthy
if(temp)
@@ -1,5 +1,5 @@
/mob/living/carbon/human/apply_damage(damage = 0,damagetype = BRUTE, def_zone = null, blocked = FALSE, forced = FALSE)
/mob/living/carbon/human/apply_damage(damage = 0,damagetype = BRUTE, def_zone = null, blocked = FALSE, forced = FALSE, spread_damage)
// depending on the species, it will run the corresponding apply_damage code there
return dna.species.apply_damage(damage, damagetype, def_zone, blocked, src, forced)
return dna.species.apply_damage(damage, damagetype, def_zone, blocked, src, forced, spread_damage)
@@ -159,7 +159,10 @@
disabled += BP
missing -= BP.body_zone
for(var/obj/item/I in BP.embedded_objects)
msg += "<B>[t_He] [t_has] \a [icon2html(I, user)] [I] embedded in [t_his] [BP.name]!</B>\n"
if(I.isEmbedHarmless())
msg += "<B>[t_He] [t_has] \a [icon2html(I, user)] [I] stuck to [t_his] [BP.name]!</B>\n"
else
msg += "<B>[t_He] [t_has] \a [icon2html(I, user)] [I] embedded in [t_his] [BP.name]!</B>\n"
for(var/X in disabled)
var/obj/item/bodypart/BP = X

Some files were not shown because too many files have changed in this diff Show More