Merge branch 'master' into silicons-patch-1

This commit is contained in:
silicons
2021-10-06 07:21:45 -07:00
committed by GitHub
150 changed files with 7898 additions and 4679 deletions

View File

@@ -226,16 +226,16 @@
user.mind.AddSpell(new /obj/effect/proc_holder/spell/targeted/shed_human_form)
if(!ishuman(user))
return
var/mob/living/carbon/human/H = user
H.physiology.brute_mod *= 0.5
H.physiology.burn_mod *= 0.5
var/datum/antagonist/heretic/heretic = user.mind.has_antag_datum(/datum/antagonist/heretic)
var/datum/eldritch_knowledge/flesh_grasp/ghoul1 = heretic.get_knowledge(/datum/eldritch_knowledge/flesh_grasp)
ghoul1.ghoul_amt *= 3
var/datum/eldritch_knowledge/flesh_ghoul/ghoul2 = heretic.get_knowledge(/datum/eldritch_knowledge/flesh_ghoul)
ghoul2.max_amt *= 3
var/mob/living/carbon/human/lord_of_arms = user
lord_of_arms.physiology.brute_mod *= 0.5
lord_of_arms.physiology.burn_mod *= 0.5
lord_of_arms.client?.give_award(/datum/award/achievement/misc/flesh_ascension, lord_of_arms)
var/datum/antagonist/heretic/heretic_datum = user.mind.has_antag_datum(/datum/antagonist/heretic)
var/datum/eldritch_knowledge/flesh_grasp/grasp_ghoul = heretic_datum.get_knowledge(/datum/eldritch_knowledge/flesh_grasp)
grasp_ghoul.ghoul_amt *= 3
var/datum/eldritch_knowledge/flesh_ghoul/better_ghoul = heretic_datum.get_knowledge(/datum/eldritch_knowledge/flesh_ghoul)
better_ghoul.max_amt *= 3
return ..()
/datum/eldritch_knowledge/flesh_blade_upgrade_2
name = "Remembrance"

View File

@@ -181,13 +181,13 @@
var/mob/living/carbon/human/H = user
H.physiology.brute_mod *= 0.5
H.physiology.burn_mod *= 0.5
H.client?.give_award(/datum/award/achievement/misc/rust_ascension, H)
priority_announce("$^@&#*$^@(#&$(@&#^$&#^@# Fear the decay, for the Rustbringer, [user.real_name] has ascended! None shall escape the corrosion! $^@&#*$^@(#&$(@&#^$&#^@#","#$^@&#*$^@(#&$(@&#^$&#^@#", 'sound/announcer/classic/spanomalies.ogg')
new /datum/rust_spread(loc)
var/datum/antagonist/heretic/ascension = H.mind.has_antag_datum(/datum/antagonist/heretic)
ascension.ascended = TRUE
return ..()
/datum/eldritch_knowledge/final/rust_final/on_life(mob/user)
. = ..()
if(!finished)

View File

@@ -183,14 +183,14 @@
var/datum/weather/void_storm/storm
/datum/eldritch_knowledge/final/void_final/on_finished_recipe(mob/living/user, list/atoms, loc)
var/mob/living/carbon/human/H = user
user.mind.AddSpell(new /obj/effect/proc_holder/spell/aoe_turf/repulse/eldritch)
H.physiology.brute_mod *= 0.5
H.physiology.burn_mod *= 0.5
ADD_TRAIT(H, TRAIT_RESISTLOWPRESSURE, MAGIC_TRAIT)
priority_announce("$^@&#*$^@(#&$(@&#^$&#^@# The nobleman of void [H.real_name] has arrived, step along the Waltz that ends worlds! $^@&#*$^@(#&$(@&#^$&#^@#","#$^@&#*$^@(#&$(@&#^$&#^@#", 'sound/announcer/classic/spanomalies.ogg')
sound_loop = new(list(user),TRUE,TRUE)
var/mob/living/carbon/human/waltzing = user
waltzing.mind.AddSpell(new /obj/effect/proc_holder/spell/aoe_turf/repulse/eldritch)
waltzing.physiology.brute_mod *= 0.5
waltzing.physiology.burn_mod *= 0.5
ADD_TRAIT(waltzing, TRAIT_RESISTLOWPRESSURE, MAGIC_TRAIT)
waltzing.client?.give_award(/datum/award/achievement/misc/void_ascension, waltzing)
priority_announce("$^@&#*$^@(#&$(@&#^$&#^@# The nobleman of void [waltzing.real_name] has arrived, step along the Waltz that ends worlds! $^@&#*$^@(#&$(@&#^$&#^@#","#$^@&#*$^@(#&$(@&#^$&#^@#", 'sound/announcer/classic/spanomalies.ogg')
sound_loop = new(user, TRUE, TRUE)
return ..()
/datum/eldritch_knowledge/final/void_final/on_death()

View File

@@ -50,6 +50,14 @@
A.death()
return ..()
/obj/item/soulstone/proc/hot_potato(mob/living/user)
to_chat(user, span_userdanger("Holy magics residing in \the [src] burn your hand!"))
var/obj/item/bodypart/affecting = user.get_bodypart("[(user.active_hand_index % 2 == 0) ? "r" : "l" ]_arm")
affecting.receive_damage( 0, 10 ) // 10 burn damage
user.emote("scream")
user.update_damage_overlays()
user.dropItemToGround(src)
//////////////////////////////Capturing////////////////////////////////////////////////////////
/obj/item/soulstone/attack(mob/living/carbon/human/M, mob/living/user)
@@ -94,6 +102,35 @@
to_chat(A, "<b>You have been released from your prison, but you are still bound to the cult's will. Help them succeed in their goals at all costs.</b>")
was_used()
/obj/item/soulstone/pre_attack(atom/A, mob/living/user, params)
var/mob/living/simple_animal/hostile/construct/shade/occupant = (locate() in src)
var/obj/item/storage/toolbox/mechanical/target_toolbox = A
if(!occupant || !istype(target_toolbox) || target_toolbox.has_soul)
return ..()
if(iscultist(user))
hot_potato(user)
return
if(!iscultist(user, TRUE) && !iswizard(user) && !usability)
user.Unconscious(10 SECONDS)
to_chat(user, span_userdanger("Your body is wracked with debilitating pain!"))
return
user.visible_message("<span class='notice'>[user] holds [src] above [user.p_their()] head and forces it into [target_toolbox] with a flash of light!", \
span_notice("You hold [src] above your head briefly, then force it into [target_toolbox], transferring the [occupant]'s soul!"), ignored_mobs = occupant)
to_chat(occupant, span_userdanger("[user] holds you up briefly, then forces you into [target_toolbox]!"))
to_chat(occupant, span_deadsay("<b>Your eternal soul has been sacrificed to restore the soul of a toolbox. Them's the breaks!</b>"))
occupant.client?.give_award(/datum/award/achievement/misc/toolbox_soul, occupant)
occupant.deathmessage = "shrieks out in unholy pain as [occupant.p_their()] soul is absorbed into [target_toolbox]!"
release_shades(user, TRUE)
occupant.death()
target_toolbox.name = "soulful toolbox"
target_toolbox.icon_state = "toolbox_blue_old"
target_toolbox.has_soul = TRUE
target_toolbox.has_latches = FALSE
///////////////////////////Transferring to constructs/////////////////////////////////////////////////////
/obj/structure/constructshell
name = "empty shell"

View File

@@ -11,6 +11,10 @@ GLOBAL_LIST_EMPTY(asset_datums)
/datum/asset
var/_abstract = /datum/asset
var/cached_url_mappings
/// Whether or not this asset should be loaded in the "early assets" SS
var/early = FALSE
/datum/asset/New()
GLOB.asset_datums[type] = src
@@ -19,6 +23,13 @@ GLOBAL_LIST_EMPTY(asset_datums)
/datum/asset/proc/get_url_mappings()
return list()
/// Returns a cached tgui message of URL mappings
/datum/asset/proc/get_serialized_url_mappings()
if (isnull(cached_url_mappings))
cached_url_mappings = TGUI_CREATE_MESSAGE("asset/mappings", get_url_mappings())
return cached_url_mappings
/datum/asset/proc/register()
return
@@ -169,6 +180,8 @@ GLOBAL_LIST_EMPTY(asset_datums)
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
//any sprite modifications we want to do (aka, coloring a greyscaled asset)
I = ModifyInserted(I)
var/size_id = "[I.Width()]x[I.Height()]"
var/size = sizes[size_id]
@@ -185,6 +198,15 @@ GLOBAL_LIST_EMPTY(asset_datums)
sizes[size_id] = size = list(1, I, null)
sprites[sprite_name] = list(size_id, 0)
/**
* A simple proc handing the Icon for you to modify before it gets turned into an asset.
*
* Arguments:
* * I: icon being turned into an asset
*/
/datum/asset/spritesheet/proc/ModifyInserted(icon/pre_asset)
return pre_asset
/datum/asset/spritesheet/proc/InsertAll(prefix, icon/I, list/directions)
if (length(prefix))
prefix = "[prefix]-"
@@ -217,6 +239,19 @@ GLOBAL_LIST_EMPTY(asset_datums)
var/size_id = sprite[SPR_SIZE]
return {"[name][size_id] [sprite_name]"}
/**
* Returns the size class (ex design32x32) for a given sprite's icon
*
* Arguments:
* * sprite_name - The sprite to get the size of
*/
/datum/asset/spritesheet/proc/icon_size_id(sprite_name)
var/sprite = sprites[sprite_name]
if (!sprite)
return null
var/size_id = sprite[SPR_SIZE]
return "[name][size_id]"
#undef SPR_SIZE
#undef SPR_IDX
#undef SPRSZ_COUNT
@@ -224,6 +259,24 @@ GLOBAL_LIST_EMPTY(asset_datums)
#undef SPRSZ_STRIPPED
/datum/asset/changelog_item
_abstract = /datum/asset/changelog_item
var/item_filename
/datum/asset/changelog_item/New(date)
item_filename = sanitize_filename("[date].yml")
SSassets.transport.register_asset(item_filename, file("html/changelogs/archive/" + item_filename))
/datum/asset/changelog_item/send(client)
if (!item_filename)
return
. = SSassets.transport.send_assets(client, item_filename)
/datum/asset/changelog_item/get_url_mappings()
if (!item_filename)
return
. = list("[item_filename]" = SSassets.transport.get_asset_url(item_filename))
/datum/asset/spritesheet/simple
_abstract = /datum/asset/spritesheet/simple
var/list/assets
@@ -315,3 +368,28 @@ GLOBAL_LIST_EMPTY(asset_datums)
/datum/asset/simple/namespaced/proc/get_htmlloader(filename)
return url2htmlloader(SSassets.transport.get_asset_url(filename, assets[filename]))
/// A subtype to generate a JSON file from a list
/datum/asset/json
_abstract = /datum/asset/json
/// The filename, will be suffixed with ".json"
var/name
/datum/asset/json/send(client)
return SSassets.transport.send_assets(client, "data/[name].json")
/datum/asset/json/get_url_mappings()
return list(
"[name].json" = SSassets.transport.get_asset_url("data/[name].json"),
)
/datum/asset/json/register()
var/filename = "data/[name].json"
fdel(filename)
text2file(json_encode(generate()), filename)
SSassets.transport.register_asset(filename, fcopy_rsc(filename))
fdel(filename)
/// Returns the data that will be JSON encoded
/datum/asset/json/proc/generate()
SHOULD_CALL_PARENT(FALSE)
CRASH("generate() not implemented for [type]!")

View File

@@ -235,7 +235,7 @@
. += "can-open"
if(connected_port)
. += "can-connector"
var/pressure = air_contents.return_pressure()
var/pressure = air_contents?.return_pressure()
if(pressure >= 40 * ONE_ATMOSPHERE)
. += "can-o3"
else if(pressure >= 10 * ONE_ATMOSPHERE)
@@ -295,6 +295,7 @@
density = FALSE
playsound(src.loc, 'sound/effects/spray.ogg', 10, TRUE, -3)
investigate_log("was destroyed.", INVESTIGATE_ATMOS)
update_icon_state()
if(holding)
holding.forceMove(T)

View File

@@ -211,11 +211,6 @@
unit_name = "arrow"
export_types = list(/obj/item/ammo_casing/caseless/arrow, /obj/item/ammo_casing/caseless/arrow/bone, /obj/item/ammo_casing/caseless/arrow/ash)
/datum/export/weapon/bow_teaching
cost = 500
unit_name = "bowyery tablet"
export_types = list(/obj/item/book/granter/crafting_recipe/bone_bow)
/datum/export/weapon/quiver
cost = 100
unit_name = "quiver"

View File

@@ -128,6 +128,9 @@
return data
/obj/machinery/computer/cargo/express/ui_act(action, params, datum/tgui/ui)
. = ..()
if(.)
return
switch(action)
if("LZCargo")
usingBeacon = FALSE

View File

@@ -67,6 +67,20 @@
resistance_flags = NONE
strip_mod = 1.2 // because apparently black gloves had this
/obj/item/clothing/gloves/tackler/combat/goliath
name = "goliath gloves"
desc = "Rudimentary tackling gloves. The goliath hide makes it great for grappling with targets, while also being fireproof."
icon = 'icons/obj/mining.dmi'
icon_state = "goligloves"
item_state = "goligloves"
tackle_stam_cost = 25
base_knockdown = 1 SECONDS
tackle_range = 5
tackle_speed = 2
min_distance = 2
skill_mod = 1
/obj/item/clothing/gloves/tackler/combat/insulated
name = "guerrilla gloves"
desc = "Superior quality combative gloves, good for performing tackle takedowns as well as absorbing electrical shocks."

View File

@@ -427,25 +427,30 @@
desc = "Comfy and supposedly flammable."
icon_state = "flannel"
item_state = "flannel"
/obj/item/clothing/suit/jacket/flannel/red
/obj/item/clothing/suit/toggle/jacket/flannel/red
name = "red flannel jacket"
desc = "Comfy and supposedly flammable."
icon_state = "flannel_red"
item_state = "flannel_red"
/obj/item/clothing/suit/jacket/flannel/aqua
togglename = "buttons"
/obj/item/clothing/suit/toggle/jacket/flannel/aqua
name = "aqua flannel jacket"
desc = "Comfy and supposedly flammable."
icon_state = "flannel_aqua"
item_state = "flannel_aqua"
/obj/item/clothing/suit/jacket/flannel/brown
togglename = "buttons"
/obj/item/clothing/suit/toggle/jacket/flannel/brown
name = "brown flannel jacket"
desc = "Comfy and supposedly flammable."
icon_state = "flannel_brown"
item_state = "flannel_brown"
togglename = "buttons"
/obj/item/clothing/suit/toggle/jacket/whitehoodie
name = "soft hoodie"
desc = "A soft hoodie with a TailorCo brand on the tag."
icon_state = "white_hoodie"
item_state = "white_hoodie"
togglename = "zipper"
/obj/item/clothing/suit/jacket/purplehoodie
name = "purple hoodie"
desc = "A soft purple hoodie with a TailorCo brand on the tag."
@@ -482,6 +487,24 @@
icon_state = "gothic_shirtcross"
item_state = "gothic_shirtcross"
/obj/item/clothing/suit/jacket/gentlecoat
name = "grey jacket"
desc = "A grey coat with a TailorCo brand on the tag. Looks expensive."
icon_state = "gentlecoat"
item_state = "gentlecoat"
/obj/item/clothing/suit/toggle/jacket/greenjacket
name = "green outdoorsmans jacket"
desc = "A green jacket with a TailorCo brand on the tag. Looks expensive."
icon_state = "coatar"
item_state = "coatar"
togglename = "zipper"
/obj/item/clothing/suit/toggle/jacket/fancytrench
name = "grey trenchcoat"
desc = "A custom-tailored trenchcoat with a TailorCo brand on the tag."
icon_state = "fancytrench"
item_state = "fancytrench"
togglename = "buttons"
/obj/item/clothing/suit/jacket/leather
name = "leather jacket"
desc = "Pompadour not included."

View File

@@ -24,7 +24,8 @@
/area/holodeck,
/area/shuttle,
/area/maintenance,
/area/science/test_area)
/area/science/test_area,
/area/commons/cryopod)
)
//Subtypes from the above that actually should explode.

View File

@@ -84,6 +84,12 @@
user.visible_message("<span class='suicide'>[user] is scratching [user.p_their()] back as hard as [user.p_they()] can with \the [src]! It looks like [user.p_theyre()] trying to commit suicide!</span>")
return (BRUTELOSS)
/obj/item/cultivator/bone
name = "bone cultivator"
desc = "A handle and a few bones tied together to resemble a hoe. Should work for removing weeds."
icon = 'icons/obj/mining.dmi'
icon_state = "cultivator_bone"
/obj/item/hatchet
name = "hatchet"
desc = "A very sharp axe blade upon a short fibremetal handle. It has a long history of chopping things, but now it is used for chopping wood."
@@ -112,6 +118,12 @@
playsound(src, 'sound/weapons/bladeslice.ogg', 50, 1, -1)
return (BRUTELOSS)
/obj/item/hatchet/bone
name = "bone hatchet"
desc = "A primitive hatchet made out of mostly bone, with some sinew to keep it together. It just might do for cutting logs into planks."
icon = 'icons/obj/mining.dmi'
icon_state = "hatchet_bone"
/obj/item/scythe
icon_state = "scythe0"
lefthand_file = 'icons/mob/inhands/weapons/polearms_lefthand.dmi'

View File

@@ -7,11 +7,11 @@
instrument_flags = INSTRUMENT_LEGACY
volume_multiplier = 1 //not as loud as synth'd
/datum/instrument/hardcoded/accordian
name = "Accordian"
id = "accordian"
/datum/instrument/hardcoded/accordion
name = "Accordion"
id = "accordion"
legacy_instrument_ext = "mid"
legacy_instrument_path = "accordian"
legacy_instrument_path = "accordion"
/datum/instrument/hardcoded/bikehorn
name = "Bike Horn"

View File

@@ -19,8 +19,8 @@
"60"='sound/instruments/synthesis_samples/organ/crisis_hammond/c4.ogg',
"72"='sound/instruments/synthesis_samples/organ/crisis_hammond/c5.ogg')
/datum/instrument/organ/crisis_accordian
name = "Crisis Accordian"
/datum/instrument/organ/crisis_accordion
name = "Crisis Accordion"
id = "crack"
real_samples = list("36"='sound/instruments/synthesis_samples/organ/crisis_accordian/c2.ogg',
"48"='sound/instruments/synthesis_samples/organ/crisis_accordian/c3.ogg',
@@ -34,8 +34,8 @@
"60"='sound/instruments/synthesis_samples/organ/crisis_harmonica/c4.ogg',
"72"='sound/instruments/synthesis_samples/organ/crisis_harmonica/c5.ogg')
/datum/instrument/organ/crisis_tango_accordian
name = "Crisis Tango Accordian"
/datum/instrument/organ/crisis_tango_accordion
name = "Crisis Tango Accordion"
id = "crtango"
real_samples = list("36"='sound/instruments/synthesis_samples/organ/crisis_tangaccordian/c2.ogg',
"48"='sound/instruments/synthesis_samples/organ/crisis_tangaccordian/c3.ogg',

View File

@@ -13,6 +13,15 @@
display_order = JOB_DISPLAY_ORDER_PRISONER
/datum/job/prisoner/after_spawn(mob/living/carbon/human/H, mob/M)
var/list/policies = CONFIG_GET(keyed_list/policy)
var/policy = policies[POLICYCONFIG_JOB_PRISONER]
if(policy)
var/mob/found = (M?.client && M) || (H?.client && H)
to_chat(found, "<br><span class='userdanger'>!!READ THIS!!</span><br><span class='warning'>The following is server-specific policy configuration and overrides anything said above if conflicting.</span>")
to_chat(found, "<br><br>")
to_chat(found, "<span class='boldnotice'>[policy]</span>")
/datum/outfit/job/prisoner
name = "Prisoner"
jobtype = /datum/job/prisoner

View File

@@ -232,6 +232,9 @@
return data
/obj/structure/chisel_message/ui_act(action, params, datum/tgui/ui)
. = ..()
if(.)
return
var/mob/user = usr
var/is_admin = check_rights_for(user.client, R_ADMIN)
var/is_creator = user.ckey == creator_key

View File

@@ -228,6 +228,13 @@
/obj/item/kinetic_crusher/glaive/update_icon_state()
item_state = "crusher[wielded]-glaive" // this is not icon_state and not supported by 2hcomponent
/obj/item/kinetic_crusher/glaive/bone
name = "necropolis bone glaive"
desc = "Tribals trying to immitate technology have spent a long time to somehow assemble bits and pieces to work together just like the real thing. \
Although it does take a lot of effort and luck to create, it was a success."
icon_state = "crusher-bone"
item_state = "crusher0-bone"
//destablizing force
/obj/item/projectile/destabilizer
name = "destabilizing force"

View File

@@ -179,6 +179,12 @@
custom_materials = list(/datum/material/iron=50)
w_class = WEIGHT_CLASS_SMALL
/obj/item/shovel/spade/bone
name = "bone spade"
desc = "A bone spade, suitable for digging and moving dirt."
icon_state = "spade_bone"
toolspeed = 0.75
/obj/item/shovel/serrated
name = "serrated bone shovel"
desc = "A wicked tool that cleaves through dirt just as easily as it does flesh. The design was styled after ancient lavaland tribal designs."

View File

@@ -25,9 +25,6 @@
else
emp_damage = max(emp_damage-1, 0)
/mob/living/brain/handle_status_effects()
return
/mob/living/brain/handle_traits()
return

View File

@@ -22,7 +22,7 @@
/mob/living/carbon/Moved()
. = ..()
if(. && (movement_type & FLOATING)) //floating is easy
if(. && !CHECK_BITFIELD(movement_type, FLOATING)) //floating is easy
if(HAS_TRAIT(src, TRAIT_NOHUNGER))
set_nutrition(NUTRITION_LEVEL_FED - 1) //just less than feeling vigorous
else if(nutrition && stat != DEAD)

View File

@@ -83,6 +83,33 @@
. += "Chemical Storage: [changeling.chem_charges]/[changeling.chem_storage]"
. += "Absorbed DNA: [changeling.absorbedcount]"
//NINJACODE
if(istype(wear_suit, /obj/item/clothing/suit/space/space_ninja)) //Only display if actually a ninja.
var/obj/item/clothing/suit/space/space_ninja/SN = wear_suit
. += "SpiderOS Status: [SN.s_initialized ? "Initialized" : "Disabled"]"
. += "Current Time: [STATION_TIME_TIMESTAMP("hh:mm:ss", world.time)]"
if(SN.s_initialized)
//Suit gear
. += "Energy Charge: [round(SN.cell.charge/100)]%"
//Ninja status
. += "Fingerprints: [md5(dna.uni_identity)]"
. += "Unique Identity: [dna.unique_enzymes]"
. += "Overall Status: [stat > 1 ? "dead" : "[health]% healthy"]"
. += "Nutrition Status: [nutrition]"
. += "Oxygen Loss: [getOxyLoss()]"
. += "Toxin Levels: [getToxLoss()]"
. += "Burn Severity: [getFireLoss()]"
. += "Brute Trauma: [getBruteLoss()]"
. += "Radiation Levels: [radiation] rad"
. += "Body Temperature: [bodytemperature-T0C] degrees C ([bodytemperature*1.8-459.67] degrees F)"
//Diseases
if(length(diseases))
. += "Viruses:"
for(var/thing in diseases)
var/datum/disease/D = thing
. += "* [D.name], Type: [D.spread_text], Stage: [D.stage]/[D.max_stages], Possible Cure: [D.cure_text]"
/mob/living/carbon/human/show_inv(mob/user)
user.set_machine(src)
var/has_breathable_mask = istype(wear_mask, /obj/item/clothing/mask)

View File

@@ -1397,7 +1397,7 @@ GLOBAL_LIST_EMPTY(roundstart_race_names)
////////////
/datum/species/proc/handle_digestion(mob/living/carbon/human/H)
if(HAS_TRAIT(src, TRAIT_NOHUNGER))
if(HAS_TRAIT(H, TRAIT_NOHUNGER))
return //hunger is for BABIES
//The fucking TRAIT_FAT mutation is the dumbest shit ever. It makes the code so difficult to work with

View File

@@ -570,24 +570,15 @@ GLOBAL_LIST_INIT(ballmer_windows_me_msg, list("Yo man, what if, we like, uh, put
else
SEND_SIGNAL(src, COMSIG_CLEAR_MOOD_EVENT, "jittery")
if(stuttering)
stuttering = max(stuttering-1, 0)
if(druggy)
adjust_drugginess(-1)
if(slurring || drunkenness)
slurring = max(slurring-1,0,drunkenness)
if(cultslurring)
cultslurring = max(cultslurring-1, 0)
if(clockcultslurring)
clockcultslurring = max(clockcultslurring-1, 0)
if(drunkenness)
drunkenness = max(drunkenness-1,0)
if(silent)
silent = max(silent-1, 0)
if(druggy)
adjust_drugginess(-1)
if(hallucination)
handle_hallucinations()

View File

@@ -150,11 +150,26 @@
/mob/living/proc/handle_stomach()
return
//this updates all special effects: knockdown, druggy, stuttering, etc..
/*
* this updates some effects: mostly old stuff such as drunkness, druggy, stuttering, etc.
* that should be converted to status effect datums one day.
*/
/mob/living/proc/handle_status_effects()
if(confused)
confused = max(0, confused - 1)
if(stuttering)
stuttering = max(stuttering-1, 0)
if(slurring)
slurring = max(slurring-1,0)
if(cultslurring)
cultslurring = max(cultslurring-1, 0)
if(clockcultslurring)
clockcultslurring = max(clockcultslurring-1, 0)
/mob/living/proc/handle_traits()
//Eyes
if(eye_blind) //blindness, heals slowly over time

View File

@@ -166,7 +166,7 @@ GLOBAL_LIST_EMPTY(block_parry_data)
/// Clickdelay duration post-parry if you fail to parry an attack
var/parry_failed_clickcd_duration = 0 SECONDS
/// Parry cooldown post-parry if failed. This is ADDED to parry_cooldown!!!
var/parry_failed_cooldown_duration = 0 SECONDS
var/parry_failed_cooldown_duration = 3.5 SECONDS
// Advanced
/// Flags added to return value

View File

@@ -1,5 +1,3 @@
#define PAI_EMP_SILENCE_DURATION 3 MINUTES
/mob/living/silicon/pai/blob_act(obj/structure/blob/B)
return FALSE
@@ -9,7 +7,7 @@
return
take_holo_damage(severity/2)
DefaultCombatKnockdown(severity*4)
silent = max(silent, (PAI_EMP_SILENCE_DURATION) / SSmobs.wait / severity)
short_radio()
if(holoform)
fold_in(force = TRUE)
emitter_next_use = world.time + emitter_emp_cd

View File

@@ -66,6 +66,7 @@ GLOBAL_LIST(bad_gremlin_items)
/mob/living/simple_animal/hostile/gremlin/Initialize()
. = ..()
AddElement(/datum/element/ventcrawling, given_tier = VENTCRAWLER_ALWAYS)
ADD_TRAIT(src, TRAIT_SHOCKIMMUNE, INNATE_TRAIT)
access_card = new /obj/item/card/id(src)
var/datum/job/captain/C = new /datum/job/captain
access_card.access = C.get_access()

View File

@@ -95,20 +95,78 @@
/mob/living/simple_animal/hostile/carp/cayenne
name = "Cayenne"
real_name = "Cayenne"
desc = "A failed Syndicate experiment in weaponized space carp technology, it now serves as a lovable mascot."
gender = FEMALE
regen_amount = 8
speak_emote = list("squeaks")
maxHealth = 90
health = 90
gold_core_spawnable = NO_SPAWN
faction = list(ROLE_SYNDICATE, "carp") //They are still a carp
AIStatus = AI_OFF
gold_core_spawnable = NO_SPAWN
faction = list(ROLE_SYNDICATE)
/// Keeping track of the nuke disk for the functionality of storing it.
var/obj/item/disk/nuclear/disky
/// Location of the file storing disk overlays
// var/icon/disk_overlay_file = 'icons/mob/carp.dmi'
/// Colored disk mouth appearance for adding it as a mouth overlay
var/mutable_appearance/colored_disk_mouth
harm_intent_damage = 12
obj_damage = 70
melee_damage_lower = 15
melee_damage_upper = 18
/mob/living/simple_animal/hostile/carp/cayenne/Initialize()
. = ..()
// AddElement(/datum/element/pet_bonus, "bloops happily!")
// colored_disk_mouth = mutable_appearance(SSgreyscale.GetColoredIconByType(/datum/greyscale_config/carp/disk_mouth, greyscale_colors), "disk_mouth")
ADD_TRAIT(src, TRAIT_DISK_VERIFIER, INNATE_TRAIT) //carp can verify disky
/mob/living/simple_animal/hostile/carp/cayenne/IsAdvancedToolUser()
return TRUE //carp SMART
/mob/living/simple_animal/hostile/carp/cayenne/death(gibbed)
if(disky)
disky.forceMove(drop_location())
disky = null
return ..()
/mob/living/simple_animal/hostile/carp/cayenne/Destroy(force)
QDEL_NULL(disky)
return ..()
/mob/living/simple_animal/hostile/carp/cayenne/examine(mob/user)
. = ..()
if(disky)
. += span_notice("Wait... is that [disky] in [p_their()] mouth?")
/mob/living/simple_animal/hostile/carp/cayenne/AttackingTarget(atom/attacked_target)
if(istype(attacked_target, /obj/item/disk/nuclear))
var/obj/item/disk/nuclear/potential_disky = attacked_target
if(potential_disky.anchored)
return
potential_disky.forceMove(src)
disky = potential_disky
to_chat(src, span_nicegreen("YES!! You manage to pick up [disky]. (Click anywhere to place it back down.)"))
update_icon()
if(!disky.fake)
client.give_award(/datum/award/achievement/misc/cayenne_disk, src)
return
if(disky)
if(isopenturf(attacked_target))
to_chat(src, span_notice("You place [disky] on [attacked_target]"))
disky.forceMove(attacked_target.drop_location())
disky = null
update_icon()
else
disky.melee_attack_chain(src, attacked_target)
return
return ..()
/mob/living/simple_animal/hostile/carp/cayenne/Exited(atom/movable/gone, direction)
. = ..()
if(disky == gone)
disky = null
update_icon()
/mob/living/simple_animal/hostile/carp/cayenne/update_overlays()
. = ..()
if(!disky || stat == DEAD)
return
// . += colored_disk_mouth
// . += mutable_appearance(disk_overlay_file, "disk_overlay")
#undef REGENERATION_DELAY

View File

@@ -32,6 +32,9 @@ Difficulty: Hard
wander = FALSE
del_on_death = TRUE
blood_volume = BLOOD_VOLUME_NORMAL
achievement_type = /datum/award/achievement/boss/wendigo_kill
crusher_achievement_type = /datum/award/achievement/boss/wendigo_crusher
score_achievement_type = /datum/award/score/wendigo_score
deathmessage = "falls, shaking the ground around it"
deathsound = 'sound/effects/gravhit.ogg'
attack_action_types = list(/datum/action/innate/megafauna_attack/heavy_stomp,

View File

@@ -176,6 +176,12 @@ While using this makes the system rely on OnFire, it still gives options for tim
elitemind = pick(candidates)
elitemind.playsound_local(get_turf(elitemind), 'sound/effects/magic.ogg', 40, 0)
to_chat(elitemind, "<b>You have been chosen to play as a Lavaland Elite.\nIn a few seconds, you will be summoned on Lavaland as a monster to fight your activator, in a fight to the death.\nYour attacks can be switched using the buttons on the top left of the HUD, and used by clicking on targets or tiles similar to a gun.\nWhile the opponent might have an upper hand with powerful mining equipment and tools, you have great power normally limited by AI mobs.\nIf you want to win, you'll have to use your powers in creative ways to ensure the kill. It's suggested you try using them all as soon as possible.\nShould you win, you'll receive extra information regarding what to do after. Good luck!</b>")
var/list/policies = CONFIG_GET(keyed_list/policy)
var/policy = policies[POLICYCONFIG_ELITE_SPAWN]
if(policy)
to_chat(elitemind, "<br><span class='userdanger'>!!READ THIS!!</span><br><span class='warning'>The following is server-specific policy configuration and overrides anything said above if conflicting.</span>")
to_chat(elitemind, "<br><br>")
to_chat(elitemind, "<span class='boldnotice'>[policy]</span>")
addtimer(CALLBACK(src, .proc/spawn_elite, elitemind), 100)
else
visible_message("<span class='boldwarning'>The stirring stops, and nothing emerges. Perhaps try again later.</span>")
@@ -304,6 +310,12 @@ While using this makes the system rely on OnFire, it still gives options for tim
to_chat(mychild, "<span class='boldwarning'>As the life in the activator's eyes fade, the forcefield around you dies out and you feel your power subside.\nDespite this inferno being your home, you feel as if you aren't welcome here anymore.\nWithout any guidance, your purpose is now for you to decide.</span>")
to_chat(mychild, "<b>Your max health has been halved, but can now heal by standing on your tumor. Note, it's your only way to heal.\nBear in mind, if anyone interacts with your tumor, you'll be resummoned here to carry out another fight. In such a case, you will regain your full max health.\nAlso, be weary of your fellow inhabitants, they likely won't be happy to see you!</b>")
to_chat(mychild, "<span class='big bold'>Note that you are a lavaland monster, and thus not allied to the station. You should not cooperate or act friendly with any station crew unless under extreme circumstances!</span>")
var/list/policies = CONFIG_GET(keyed_list/policy)
var/policy = policies[POLICYCONFIG_ELITE_WIN]
if(policy)
to_chat(mychild, "<br><span class='userdanger'>!!READ THIS!!</span><br><span class='warning'>The following is server-specific policy configuration and overrides anything said above if conflicting.</span>")
to_chat(mychild, "<br><br>")
to_chat(mychild, "<span class='boldnotice'>[policy]</span>")
/obj/item/tumor_shard
name = "tumor shard"
@@ -332,6 +344,12 @@ While using this makes the system rely on OnFire, it still gives options for tim
E.playsound_local(get_turf(E), 'sound/effects/magic.ogg', 40, 0)
to_chat(E, "<span class='userdanger'>You have been revived by [user]. While you can't speak to them, you owe [user] a great debt. Assist [user.p_them()] in achieving [user.p_their()] goals, regardless of risk.</span")
to_chat(E, "<span class='big bold'>Note that you now share the loyalties of [user]. You are expected not to intentionally sabotage their faction unless commanded to!</span>")
var/list/policies = CONFIG_GET(keyed_list/policy)
var/policy = policies[POLICYCONFIG_ELITE_SENTIENCE]
if(policy)
to_chat(E, "<br><span class='userdanger'>!!READ THIS!!</span><br><span class='warning'>The following is server-specific policy configuration and overrides anything said above if conflicting.</span>")
to_chat(E, "<br><br>")
to_chat(E, "<span class='boldnotice'>[policy]</span>")
E.maxHealth = E.maxHealth * 0.5
E.health = E.maxHealth
E.desc = "[E.desc] However, this one appears appears less wild in nature, and calmer around people."

View File

@@ -136,7 +136,7 @@ GLOBAL_LIST_EMPTY(plague_rats)
if(LAZYLEN(GLOB.plague_rats) >= cap)
visible_message("<span class='warning'>[src] gnaws into its food, [cap] rats are now on the station!</span>")
return
var/mob/living/newmouse = new /mob/living/simple_animal/hostile/plaguerat(loc)
new /mob/living/simple_animal/hostile/plaguerat(loc)
visible_message("<span class='notice'>[src] gnaws into its food, attracting another rat!</span>")
/mob/living/simple_animal/hostile/plaguerat/proc/exit_vents()

View File

@@ -195,12 +195,6 @@
stat = CONSCIOUS
med_hud_set_status()
/mob/living/simple_animal/handle_status_effects()
..()
if(stuttering)
stuttering = 0
/mob/living/simple_animal/proc/handle_automated_action()
set waitfor = FALSE
return

View File

@@ -113,6 +113,7 @@
multiplicative_slowdown = CRAWLING_ADD_SLOWDOWN
movetypes = CRAWLING
flags = IGNORE_NOSLOW
priority = 20000
/datum/movespeed_modifier/mob_config_speedmod
variable = TRUE

View File

@@ -15,7 +15,6 @@
//Defines for the suit's unique abilities
#define IS_NINJA_SUIT_INITIALIZATION(action) (istype(action, /datum/action/item_action/initialize_ninja_suit))
#define IS_NINJA_SUIT_STATUS(action) (istype(action, /datum/action/item_action/ninjastatus))
#define IS_NINJA_SUIT_BOOST(action) (istype(action, /datum/action/item_action/ninjaboost))
#define IS_NINJA_SUIT_EMP(action) (istype(action, /datum/action/item_action/ninjapulse))
#define IS_NINJA_SUIT_STAR_CREATION(action) (istype(action, /datum/action/item_action/ninjastar))

View File

@@ -5,35 +5,3 @@
button_icon_state = "health"
icon_icon = 'icons/obj/device.dmi'
var/action_background_icon_state = "bg_default_on"
/**
* Proc called to put a status readout to the ninja in chat.
*
* Called put some information about the ninja's current status into chat.
* This information used to be displayed constantly on the status tab screen
* when the suit was on, but was turned into this as to remove the code from
* human.dm
*/
/obj/item/clothing/suit/space/space_ninja/proc/ninjastatus()
var/mob/living/carbon/human/ninja = affecting
var/list/info_list = list()
info_list += "<span class='info'>SpiderOS Status: [s_initialized ? "Initialized" : "Disabled"]</span>\n"
//Ninja status
info_list += "<span class='info'>Fingerprints: [md5(ninja.dna.uni_identity)]</span>\n"
info_list += "<span class='info'>Unique Identity: [ninja.dna.unique_enzymes]</span>\n"
info_list += "<span class='info'>Overall Status: [ninja.stat > 1 ? "dead" : "[ninja.health]% healthy"]</span>\n"
info_list += "<span class='info'>Nutrition Status: [ninja.nutrition]</span>\n"
info_list += "<span class='info'>Oxygen Loss: [ninja.getOxyLoss()]</span>\n"
info_list += "<span class='info'>Toxin Levels: [ninja.getToxLoss()]</span>\n"
info_list += "<span class='info'>Burn Severity: [ninja.getFireLoss()]</span>\n"
info_list += "<span class='info'>Brute Trauma: [ninja.getBruteLoss()]</span>\n"
info_list += "<span class='info'>Radiation Levels: [ninja.radiation] rad</span>\n"
info_list += "<span class='info'>Body Temperature: [ninja.bodytemperature-T0C] degrees C ([ninja.bodytemperature*1.8-459.67] degrees F)</span>\n"
//Diseases
if(length(ninja.diseases))
info_list += "Viruses:"
for(var/datum/disease/ninja_disease in ninja.diseases)
info_list += "<span class='info'>* [ninja_disease.name], Type: [ninja_disease.spread_text], Stage: [ninja_disease.stage]/[ninja_disease.max_stages], Possible Cure: [ninja_disease.cure_text]</span>\n"
to_chat(ninja, "[info_list.Join()]")

View File

@@ -121,9 +121,6 @@
if(s_coold > 0)
to_chat(user, "<span class='warning'><b>ERROR</b>: suit is on cooldown.</span>")
return FALSE
if(IS_NINJA_SUIT_STATUS(action))
ninjastatus()
return TRUE
if(IS_NINJA_SUIT_BOOST(action))
ninjaboost()
return TRUE

View File

@@ -23,4 +23,10 @@
/obj/item/ammo_box/magazine/mm712x82/match
name = "box magazine (Match 7.12x82mm)"
icon_state = "a762-50"
ammo_type = /obj/item/ammo_casing/mm712x82/match
max_ammo = 50
/obj/item/ammo_box/magazine/mm712x82/update_icon()
..()
icon_state = "a762-[round(ammo_count(),10)]"

View File

@@ -24,6 +24,7 @@
playsound(user, 'sound/weapons/shotguninsert.ogg', 60, 1)
A.update_icon()
update_icon()
user.SetNextAction(CLICK_CD_MELEE)
/obj/item/gun/ballistic/shotgun/process_chamber(mob/living/user, empty_chamber = 0)
return ..() //changed argument value
@@ -240,7 +241,7 @@
/obj/item/gun/ballistic/shotgun/automatic/combat/compact
name = "warden's combat shotgun"
desc = "A modified version of the semi automatic combat shotgun with a collapsible stock. For close encounters."
desc = "A modified version of the semi-automatic combat shotgun with a collapsible stock and a safety that prevents firing while folded. For close encounters."
icon_state = "cshotgunc"
mag_type = /obj/item/ammo_box/magazine/internal/shot/com
w_class = WEIGHT_CLASS_NORMAL
@@ -250,7 +251,7 @@
/obj/item/gun/ballistic/shotgun/automatic/combat/compact/AltClick(mob/living/user)
. = ..()
if(!istype(user) || !user.canUseTopic(src, BE_CLOSE, ismonkey(user)))
if(!istype(user) || !user.canUseTopic(src, BE_CLOSE, ismonkey(user)) || item_flags && IN_STORAGE)
return
toggle_stock(user)
return TRUE
@@ -276,6 +277,14 @@
/obj/item/gun/ballistic/shotgun/automatic/combat/compact/update_icon_state()
icon_state = "[current_skin ? unique_reskin[current_skin] : "cshotgun"][stock ? "" : "c"]"
/obj/item/gun/ballistic/shotgun/automatic/combat/compact/afterattack(atom/target, mob/living/user, flag, params)
if(!stock)
shoot_with_empty_chamber(user)
to_chat(user, "<span class='warning'>[src] won't fire with a folded stock!</span>")
else
. = ..()
update_icon()
//Dual Feed Shotgun
/obj/item/gun/ballistic/shotgun/automatic/dual_tube

View File

@@ -1,6 +1,6 @@
/obj/item/gun/magic/staff/motivation
name = "Motivation"
desc = "Rumored to have the ability to open up a portal the depths of Lavaland."
desc = "Rumored to have the ability to open up a portal to the depths of Lavaland."
icon = 'icons/obj/items_and_weapons.dmi'
icon_state = "motivation"
item_state = "motivation"
@@ -21,15 +21,15 @@
recharge_rate = 5
var/datum/action/judgement_cut/judgementcut = new/datum/action/judgement_cut()
block_parry_data = /datum/block_parry_data/motivation
//to get this to toggle correctly
/obj/item/gun/magic/staff/motivation/Initialize()
. = ..()
judgementcut = new(src)
//lets the user know that their judgment cuts are recharging
//lets the user know that their judgement cuts are recharging
/obj/item/gun/magic/staff/motivation/shoot_with_empty_chamber(mob/living/user as mob|obj)
to_chat(user, "<span class='warning'>Judgment Cut is recharging.</span>")
to_chat(user, "<span class='warning'>Judgement Cut is recharging.</span>")
//action button to toggle judgement cuts on/off
/datum/action/judgement_cut
@@ -47,7 +47,7 @@
/obj/item/gun/magic/staff/motivation/can_trigger_gun(mob/living/user)
. = ..()
if(!judgementcut.judgement_toggled)
to_chat(user, "<span class='notice'> Judgment Cut is disabled.</span>")
to_chat(user, "<span class='notice'>Judgement Cut is disabled.</span>")
return FALSE
//adds/removes judgement cut and judgement cut end upon pickup/drop

View File

@@ -84,6 +84,7 @@
else
reagents.trans_to(D, amount_per_transfer_from_this, 1/range)
D.add_atom_colour(mix_color_from_reagents(D.reagents.reagent_list), TEMPORARY_COLOUR_PRIORITY)
playsound(src.loc, 'sound/effects/spray2.ogg', 50, 1, -6)
last_spray = world.time
INVOKE_ASYNC(D, /obj/effect/decal/chempuff/proc/run_puff, A)

View File

@@ -37,7 +37,7 @@
build_path = /obj/item/storage/bag/tray
category = list("initial","Dinnerware")
/datum/design/tray
/datum/design/cafeteria_tray
name = "Cafeteria Tray"
id = "foodtray"
build_type = AUTOLATHE

View File

@@ -242,13 +242,24 @@
sleep(30)
playsound(C, 'sound/machines/defib_zap.ogg', 50, FALSE)
if(check_revivable())
var/tplus = world.time - C.timeofdeath
playsound(C, 'sound/machines/defib_success.ogg', 50, FALSE)
C.set_heartattack(FALSE)
var/oxydamage = C.getOxyLoss()
if(C.health < HEALTH_THRESHOLD_FULLCRIT && oxydamage)
var/diff = C.health - HEALTH_THRESHOLD_FULLCRIT
C.adjustOxyLoss(diff) //Heal their oxydamage up to hardcrit (or if less, as much as they have, since the proc has sanity)
C.revive(full_heal = FALSE, admin_revive = FALSE)
C.emote("gasp")
C.Jitter(100)
SEND_SIGNAL(C, COMSIG_LIVING_MINOR_SHOCK)
log_game("[C] has been successfully defibrillated by nanites.")
var/list/policies = CONFIG_GET(keyed_list/policy)
var/timelimit = CONFIG_GET(number/defib_cmd_time_limit) * 10 //the config is in seconds, not deciseconds
var/late = timelimit && (tplus > timelimit)
var/policy = late? policies[POLICYCONFIG_ON_DEFIB_LATE] : policies[POLICYCONFIG_ON_DEFIB_INTACT]
if(policy)
to_chat(C, policy)
C.log_message("has been successfully defibrillated by nanites, [tplus] deciseconds from time of death, considered [late? "late" : "memory-intact"] revival under configured policy limits.", LOG_GAME)
else
playsound(C, 'sound/machines/defib_failed.ogg', 50, FALSE)

View File

@@ -59,13 +59,13 @@
one though."
icon_state = "default_human_l_arm"
attack_verb = list("slapped", "punched")
max_damage = 150
max_damage = 50
disable_threshold = 75
max_stamina_damage = 50
body_zone = BODY_ZONE_L_ARM
body_part = ARM_LEFT
aux_icons = list(BODY_ZONE_PRECISE_L_HAND = HANDS_PART_LAYER, "l_hand_behind" = BODY_BEHIND_LAYER)
body_damage_coeff = 0.25
body_damage_coeff = 0.75
held_index = 1
px_x = -6
px_y = 0
@@ -121,12 +121,12 @@
among humans missing their right arm."
icon_state = "default_human_r_arm"
attack_verb = list("slapped", "punched")
max_damage = 150
max_damage = 50
disable_threshold = 75
body_zone = BODY_ZONE_R_ARM
body_part = ARM_RIGHT
aux_icons = list(BODY_ZONE_PRECISE_R_HAND = HANDS_PART_LAYER, "r_hand_behind" = BODY_BEHIND_LAYER)
body_damage_coeff = 0.25
body_damage_coeff = 0.75
held_index = 2
px_x = 6
px_y = 0
@@ -184,11 +184,11 @@
luck. In this instance, it probably would not have helped."
icon_state = "default_human_l_leg"
attack_verb = list("kicked", "stomped")
max_damage = 150
max_damage = 50
disable_threshold = 75
body_zone = BODY_ZONE_L_LEG
body_part = LEG_LEFT
body_damage_coeff = 0.25
body_damage_coeff = 0.75
px_x = -2
px_y = 12
stam_heal_tick = STAM_RECOVERY_LIMB
@@ -243,11 +243,10 @@
// alternative spellings of 'pokey' are availible
icon_state = "default_human_r_leg"
attack_verb = list("kicked", "stomped")
max_damage = 150
disable_threshold = 75
max_damage = 50
body_zone = BODY_ZONE_R_LEG
body_part = LEG_RIGHT
body_damage_coeff = 0.25
body_damage_coeff = 0.75
px_x = 2
px_y = 12
max_stamina_damage = 50

View File

@@ -48,6 +48,13 @@
w_class = WEIGHT_CLASS_TINY
toolspeed = 0.5
/obj/item/retractor/ashwalker
name = "bontractor"
desc = "Kinda looks like a chicken bone."
icon = 'icons/obj/mining.dmi'
icon_state = "retractor_bone"
toolspeed = 0.85
/obj/item/hemostat
name = "hemostat"
desc = "You think you have seen this before."
@@ -78,6 +85,14 @@
toolspeed = 0.5
attack_verb = list("attacked", "pinched")
/obj/item/hemostat/ashwalker
name = "femurstat"
desc = "Bones that are strapped together with sinews. Used to stop bleeding."
icon = 'icons/obj/mining.dmi'
icon_state = "hemostat_bone"
toolspeed = 0.85
/obj/item/cautery
name = "cautery"
desc = "This stops bleeding."
@@ -108,6 +123,13 @@
toolspeed = 0.5
attack_verb = list("burnt")
/obj/item/cautery/ashwalker
name = "coretery"
desc = "A legion core strapped to a bone. It can close wounds."
icon = 'icons/obj/mining.dmi'
icon_state = "cautery_bone"
toolspeed = 0.85
/obj/item/surgicaldrill
name = "surgical drill"
desc = "You can drill using this item. You dig?"
@@ -257,6 +279,14 @@
user.visible_message("<span class='suicide'>[user] is slitting [user.p_their()] [pick("wrists", "throat", "stomach")] with [src]! It looks like [user.p_theyre()] trying to commit suicide!</span>")
return (BRUTELOSS)
/obj/item/scalpel/ashwalker
name = "diamond scalpel"
desc = "Bones and a Diamond tied together to make a scalpel."
icon = 'icons/obj/mining.dmi'
icon_state = "scalpel_bone"
force = 12
toolspeed = 0.85
/obj/item/circular_saw
name = "circular saw"
desc = "For heavy duty cutting."
@@ -309,6 +339,14 @@
attack_verb = list("attacked", "slashed", "sawed", "cut")
sharpness = SHARP_EDGED
/obj/item/circular_saw/ashwalker
name = "diamond bonesaw"
desc = "Bones designed like a skull, with diamond teeth to cut through bones."
icon = 'icons/obj/mining.dmi'
icon_state = "saw_bone"
force = 12
toolspeed = 0.85
/obj/item/surgical_drapes
name = "surgical drapes"
desc = "Nanotrasen brand surgical drapes provide optimal safety and infection control."
@@ -341,6 +379,13 @@
prototype = SSresearch.techweb_design_by_id(id)
. |= prototype.surgery
/obj/item/surgical_drapes/goliath
name = "goliath drapes"
desc = "Probably not the most hygienic but what the heck else are you gonna use?"
icon = 'icons/obj/mining.dmi'
icon_state = "surgical_drapes_goli"
/obj/item/organ_storage //allows medical cyborgs to manipulate organs without hands
name = "organ storage bag"
desc = "A container for holding body parts."
@@ -433,3 +478,10 @@
to_chat(user, "<span class='warning'>You refrain from hitting [L] with [src], as you are in help intent.</span>")
return
return ..()
/obj/item/bonesetter/bone
name = "bone bonesetter"
desc = "A bonesetter made of bones... for setting bones with... bones?"
icon = 'icons/obj/mining.dmi'
icon_state = "bone setter_bone"
toolspeed = 0.85

View File

@@ -74,7 +74,7 @@
* return bool If the user's input has been handled and the UI should update.
*/
/datum/proc/ui_act(action, list/params, datum/tgui/ui, datum/ui_state/state)
// SHOULD_CALL_PARENT(TRUE)
SHOULD_CALL_PARENT(TRUE)
// If UI is not interactive or usr calling Topic is not the UI user, bail.
if(!ui || ui.status != UI_INTERACTIVE)
return TRUE
@@ -145,6 +145,7 @@
* client/verb/uiclose(), which closes the ui window
*/
/datum/proc/ui_close(mob/user)
SIGNAL_HANDLER
/**
* verb

View File

@@ -58,11 +58,16 @@
src.interface = interface
if(title)
src.title = title
src.state = src_object.ui_state()
src.state = src_object.ui_state(user)
// Deprecated
if(ui_x && ui_y)
src.window_size = list(ui_x, ui_y)
/datum/tgui/Destroy()
user = null
src_object = null
return ..()
/**
* public
*

View File

@@ -8,8 +8,9 @@
* * title - The of the alert modal, shown on the top of the TGUI window.
* * buttons - The options that can be chosen by the user, each string is assigned a button on the UI.
* * timeout - The timeout of the alert, after which the modal will close and qdel itself. Set to zero for no timeout.
* * autofocus - The bool that controls if this alert should grab window focus.
*/
/proc/tgui_alert(mob/user, message = null, title = null, list/buttons = list("Ok"), timeout = 0)
/proc/tgui_alert(mob/user, message = null, title = null, list/buttons = list("Ok"), timeout = 0, autofocus = TRUE)
if (!user)
user = usr
if (!istype(user))
@@ -18,7 +19,7 @@
user = client.mob
else
return
var/datum/tgui_modal/alert = new(user, message, title, buttons, timeout)
var/datum/tgui_modal/alert = new(user, message, title, buttons, timeout, autofocus)
alert.ui_interact(user)
alert.wait()
if (alert)
@@ -36,8 +37,9 @@
* * buttons - The options that can be chosen by the user, each string is assigned a button on the UI.
* * callback - The callback to be invoked when a choice is made.
* * timeout - The timeout of the alert, after which the modal will close and qdel itself. Disabled by default, can be set to seconds otherwise.
* * autofocus - The bool that controls if this alert should grab window focus.
*/
/proc/tgui_alert_async(mob/user, message = null, title = null, list/buttons = list("Ok"), datum/callback/callback, timeout = 0)
/proc/tgui_alert_async(mob/user, message = null, title = null, list/buttons = list("Ok"), datum/callback/callback, timeout = 0, autofocus = TRUE)
if (!user)
user = usr
if (!istype(user))
@@ -46,7 +48,7 @@
user = client.mob
else
return
var/datum/tgui_modal/async/alert = new(user, message, title, buttons, callback, timeout)
var/datum/tgui_modal/async/alert = new(user, message, title, buttons, callback, timeout, autofocus)
alert.ui_interact(user)
/**
@@ -68,13 +70,16 @@
var/start_time
/// The lifespan of the tgui_modal, after which the window will close and delete itself.
var/timeout
/// The bool that controls if this modal should grab window focus
var/autofocus
/// Boolean field describing if the tgui_modal was closed by the user.
var/closed
/datum/tgui_modal/New(mob/user, message, title, list/buttons, timeout)
/datum/tgui_modal/New(mob/user, message, title, list/buttons, timeout, autofocus)
src.title = title
src.message = message
src.buttons = buttons.Copy()
src.autofocus = autofocus
if (timeout)
src.timeout = timeout
start_time = world.time
@@ -110,7 +115,8 @@
. = list(
"title" = title,
"message" = message,
"buttons" = buttons
"buttons" = buttons,
"autofocus" = autofocus
)
if(timeout)
@@ -140,8 +146,8 @@
/// The callback to be invoked by the tgui_modal upon having a choice made.
var/datum/callback/callback
/datum/tgui_modal/async/New(mob/user, message, title, list/buttons, callback, timeout)
..(user, message, title, buttons, timeout)
/datum/tgui_modal/async/New(mob/user, message, title, list/buttons, callback, timeout, autofocus)
..(user, message, title, buttons, timeout, autofocus)
src.callback = callback
/datum/tgui_modal/async/Destroy(force, ...)

View File

@@ -82,6 +82,7 @@
src.message = message
src.buttons = list()
src.buttons_map = list()
var/list/repeat_buttons = list()
// Gets rid of illegal characters
var/static/regex/whitelistedWords = regex(@{"([^\u0020-\u8000]+)"})
@@ -89,6 +90,9 @@
for(var/i in buttons)
var/string_key = whitelistedWords.Replace("[i]", "")
//avoids duplicated keys E.g: when areas have the same name
string_key = avoid_assoc_duplicate_keys(string_key, repeat_buttons)
src.buttons += string_key
src.buttons_map[string_key] = i
@@ -144,7 +148,7 @@
if("choose")
if (!(params["choice"] in buttons))
return
choice = buttons_map[params["choice"]]
set_choice(buttons_map[params["choice"]])
SStgui.close_uis(src)
return TRUE
if("cancel")
@@ -152,6 +156,9 @@
closed = TRUE
return TRUE
/datum/tgui_list_input/proc/set_choice(choice)
src.choice = choice
/**
* # async tgui_list_input
*
@@ -162,23 +169,17 @@
var/datum/callback/callback
/datum/tgui_list_input/async/New(mob/user, message, title, list/buttons, callback, timeout)
..(user, title, message, buttons, timeout)
..(user, message, title, buttons, timeout)
src.callback = callback
/datum/tgui_list_input/async/Destroy(force, ...)
QDEL_NULL(callback)
. = ..()
/datum/tgui_list_input/async/ui_close(mob/user)
/datum/tgui_list_input/async/set_choice(choice)
. = ..()
qdel(src)
/datum/tgui_list_input/async/ui_act(action, list/params)
. = ..()
if (!. || choice == null)
return
callback.InvokeAsync(choice)
qdel(src)
if(!isnull(src.choice))
callback?.InvokeAsync(src.choice)
/datum/tgui_list_input/async/wait()
return

View File

@@ -258,7 +258,7 @@
if(istype(asset, /datum/asset/spritesheet))
var/datum/asset/spritesheet/spritesheet = asset
send_message("asset/stylesheet", spritesheet.css_filename())
send_message("asset/mappings", asset.get_url_mappings())
send_raw_message(asset.get_serialized_url_mappings())
/**
* private

View File

@@ -292,7 +292,5 @@
desc = "An ancient blade said to have ties with Lavaland's most inner demons. \
Allows you to cut from a far distance!"
item = /obj/item/gun/magic/staff/motivation
cost = 20
player_minimum = 20
cost = 10
exclude_modes = list(/datum/game_mode/nuclear, /datum/game_mode/nuclear/clown_ops, /datum/game_mode/traitor/internal_affairs)
cant_discount = TRUE

View File

@@ -91,9 +91,9 @@
/obj/vehicle/proc/after_add_occupant(mob/M)
auto_assign_occupant_flags(M)
/obj/vehicle/proc/auto_assign_occupant_flags(mob/M) //override for each type that needs it. Default is assign driver if drivers is not at max.
/obj/vehicle/proc/auto_assign_occupant_flags(mob/M) //override for each type that needs it. Default is assign driver if drivers is not at max.
if(driver_amount() < max_drivers)
add_control_flags(M, VEHICLE_CONTROL_DRIVE|VEHICLE_CONTROL_PERMISSION)
add_control_flags(M, VEHICLE_CONTROL_DRIVE)
/obj/vehicle/proc/remove_occupant(mob/M)
if(!istype(M))

View File

@@ -16,7 +16,7 @@
. = ..()
initialize_controller_action_type(/datum/action/vehicle/sealed/remove_key, VEHICLE_CONTROL_DRIVE)
if(car_traits & CAN_KIDNAP)
initialize_controller_action_type(/datum/action/vehicle/sealed/DumpKidnappedMobs, VEHICLE_CONTROL_DRIVE)
initialize_controller_action_type(/datum/action/vehicle/sealed/dump_kidnapped_mobs, VEHICLE_CONTROL_DRIVE)
/obj/vehicle/sealed/car/driver_move(mob/user, direction)
if(key_type && !is_key(inserted_key))

View File

@@ -1,6 +1,6 @@
/obj/vehicle/sealed/car/clowncar
name = "clown car"
desc = "How someone could even fit in there is beyond me."
desc = "How someone could even fit in there is byond me."
icon_state = "clowncar"
max_integrity = 150
armor = list("melee" = 70, "bullet" = 40, "laser" = 40, "energy" = 0, "bomb" = 30, "bio" = 0, "rad" = 0, "fire" = 80, "acid" = 80)
@@ -10,25 +10,36 @@
car_traits = CAN_KIDNAP
key_type = /obj/item/bikehorn
key_type_exact = FALSE
var/droppingoil = FALSE
var/RTDcooldown = 150
var/lastRTDtime = 0
///list of headlight colors we use to pick through when we have party mode due to emag
var/headlight_colors = list(COLOR_RED, COLOR_ORANGE, COLOR_YELLOW, COLOR_LIME, COLOR_BRIGHT_BLUE, COLOR_CYAN, COLOR_PURPLE)
///Cooldown time inbetween [/obj/vehicle/sealed/car/clowncar/proc/roll_the_dice()] usages
var/dice_cooldown_time = 150
///How many times kidnappers in the clown car said thanks
var/thankscount = 0
///Current status of the cannon, alternates between CLOWN_CANNON_INACTIVE, CLOWN_CANNON_BUSY and CLOWN_CANNON_READY
var/cannonmode = CLOWN_CANNON_INACTIVE
var/light_on = TRUE
/obj/vehicle/sealed/car/clowncar/Initialize()
. = ..()
START_PROCESSING(SSobj,src)
/obj/vehicle/sealed/car/clowncar/process()
if(light_on && (obj_flags & EMAGGED))
set_light_color(pick(headlight_colors))
/obj/vehicle/sealed/car/clowncar/generate_actions()
. = ..()
initialize_controller_action_type(/datum/action/vehicle/sealed/horn/clowncar, VEHICLE_CONTROL_DRIVE)
/obj/vehicle/sealed/car/clowncar/driver_move(mob/user, direction) //Prevent it from moving onto space
if(isspaceturf(get_step(src, direction)))
return FALSE
else
return ..()
initialize_controller_action_type(/datum/action/vehicle/sealed/horn, VEHICLE_CONTROL_DRIVE)
initialize_controller_action_type(/datum/action/vehicle/sealed/thank, VEHICLE_CONTROL_KIDNAPPED)
/obj/vehicle/sealed/car/clowncar/auto_assign_occupant_flags(mob/M)
if(ishuman(M))
var/mob/living/carbon/human/H = M
if(H.mind && HAS_TRAIT(H.mind, TRAIT_CLOWN_MENTALITY)) //Ensures only clowns can drive the car. (Including more at once)
add_control_flags(M, VEHICLE_CONTROL_DRIVE|VEHICLE_CONTROL_PERMISSION)
add_control_flags(H, VEHICLE_CONTROL_DRIVE)
RegisterSignal(H, COMSIG_MOB_CLICKON, .proc/fire_cannon_at)
M.log_message("has entered [src] as a possible driver", LOG_ATTACK)
return
add_control_flags(M, VEHICLE_CONTROL_KIDNAPPED)
@@ -36,106 +47,195 @@
. = ..()
playsound(src, pick('sound/vehicles/clowncar_load1.ogg', 'sound/vehicles/clowncar_load2.ogg'), 75)
/obj/vehicle/sealed/car/clowncar/after_add_occupant(mob/M, control_flags)
. = ..()
if(return_controllers_with_flag(VEHICLE_CONTROL_KIDNAPPED).len >= 30)
for(var/mob/voreman as anything in return_drivers())
voreman.client.give_award(/datum/award/achievement/misc/round_and_full, voreman)
/obj/vehicle/sealed/car/clowncar/attack_animal(mob/living/simple_animal/user, list/modifiers)
if((user.loc != src) || user.environment_smash & (ENVIRONMENT_SMASH_WALLS|ENVIRONMENT_SMASH_RWALLS))
return ..()
/obj/vehicle/sealed/car/clowncar/mob_exit(mob/M, silent = FALSE, randomstep = FALSE)
. = ..()
UnregisterSignal(M, COMSIG_MOB_CLICKON)
/obj/vehicle/sealed/car/clowncar/take_damage(damage_amount, damage_type = BRUTE, damage_flag = 0, sound_effect = 1, attack_dir)
. = ..()
if(prob(33))
visible_message("<span class='danger'>[src] spews out a ton of space lube!</span>")
visible_message(span_danger("[src] spews out a ton of space lube!"))
new /obj/effect/particle_effect/foam(loc) //YEET
/obj/vehicle/sealed/car/clowncar/attacked_by(obj/item/I, mob/living/user, attackchain_flags = NONE, damage_multiplier = 1)
/obj/vehicle/sealed/car/clowncar/attacked_by(obj/item/I, mob/living/user)
. = ..()
if(istype(I, /obj/item/reagent_containers/food/snacks/grown/banana))
var/obj/item/reagent_containers/food/snacks/grown/banana/banana = I
obj_integrity += min(banana.seed.potency, max_integrity-obj_integrity)
to_chat(user, "<span class='danger'>You use the [banana] to repair the [src]!</span>")
qdel(banana)
if(!istype(I, /obj/item/reagent_containers/food/snacks/grown/banana))
return
var/obj/item/reagent_containers/food/snacks/grown/banana/banana = I
obj_integrity += min(banana.seed.potency, max_integrity-obj_integrity)
to_chat(user, span_danger("You use the [banana] to repair the [src]!"))
qdel(banana)
/obj/vehicle/sealed/car/clowncar/Bump(atom/movable/M)
/obj/vehicle/sealed/car/clowncar/Bump(atom/bumped)
. = ..()
if(isliving(M))
if(ismegafauna(M))
if(isliving(bumped))
if(ismegafauna(bumped))
return
var/mob/living/L = M
if(iscarbon(L))
var/mob/living/carbon/C = L
C.DefaultCombatKnockdown(40) //I play to make sprites go horizontal
L.visible_message("<span class='warning'>[src] rams into [L] and sucks him up!</span>") //fuck off shezza this isn't ERP.
mob_forced_enter(L)
var/mob/living/hittarget_living = bumped
if(iscarbon(hittarget_living))
var/mob/living/carbon/carb = hittarget_living
carb.DefaultCombatKnockdown(40) //I play to make sprites go horizontal
hittarget_living.visible_message(span_warning("[src] rams into [hittarget_living] and sucks [hittarget_living.p_them()] up!")) //fuck off shezza this isn't ERP.
mob_forced_enter(hittarget_living)
playsound(src, pick('sound/vehicles/clowncar_ram1.ogg', 'sound/vehicles/clowncar_ram2.ogg', 'sound/vehicles/clowncar_ram3.ogg'), 75)
else if(istype(M, /turf/closed) || istype(M, /obj/machinery/door/airlock/external))
visible_message("<span class='warning'>[src] rams into [M] and crashes!</span>")
playsound(src, pick('sound/vehicles/clowncar_crash1.ogg', 'sound/vehicles/clowncar_crash2.ogg'), 75)
playsound(src, 'sound/vehicles/clowncar_crashpins.ogg', 75)
DumpMobs(TRUE)
log_combat(src, hittarget_living, "sucked up")
return
if(!istype(bumped, /turf/closed))
return
visible_message(span_warning("[src] rams into [bumped] and crashes!"))
playsound(src, pick('sound/vehicles/clowncar_crash1.ogg', 'sound/vehicles/clowncar_crash2.ogg'), 75)
playsound(src, 'sound/vehicles/clowncar_crashpins.ogg', 75)
DumpMobs(TRUE)
log_combat(src, bumped, "crashed into", null, "dumping all passengers")
/obj/vehicle/sealed/car/clowncar/emag_act(mob/user)
. = ..()
if(obj_flags & EMAGGED)
return
obj_flags |= EMAGGED
to_chat(user, "<span class='danger'>You scramble the clowncar child safety lock and a panel with 6 colorful buttons appears!</span>")
initialize_controller_action_type(/datum/action/vehicle/sealed/RollTheDice, VEHICLE_CONTROL_DRIVE)
to_chat(user, span_danger("You scramble \the [src]'s child safety lock, and a panel with six colorful buttons appears!"))
initialize_controller_action_type(/datum/action/vehicle/sealed/roll_the_dice, VEHICLE_CONTROL_DRIVE)
initialize_controller_action_type(/datum/action/vehicle/sealed/cannon, VEHICLE_CONTROL_DRIVE)
return TRUE
/obj/vehicle/sealed/car/clowncar/Destroy()
/obj/vehicle/sealed/car/clowncar/obj_destruction(damage_flag)
playsound(src, 'sound/vehicles/clowncar_fart.ogg', 100)
STOP_PROCESSING(SSobj,src)
return ..()
/obj/vehicle/sealed/car/clowncar/after_move(direction)
. = ..()
if(droppingoil)
new /obj/effect/decal/cleanable/oil/slippery(loc)
/obj/vehicle/sealed/car/clowncar/proc/RollTheDice(mob/user)
if(world.time - lastRTDtime < RTDcooldown)
to_chat(user, "<span class='notice'>The button panel is currently recharging.</span>")
/**
* Plays a random funky effect
* Only available while car is emagged
* Possible effects:
* * Spawn bananapeel
* * Spawn random reagent foam
* * Make the clown car look like a singulo temporarily
* * Spawn Laughing chem gas
* * Drop oil
* * Fart and make everyone nearby laugh
*/
/obj/vehicle/sealed/car/clowncar/proc/roll_the_dice(mob/user)
if(TIMER_COOLDOWN_CHECK(src, COOLDOWN_CLOWNCAR_RANDOMNESS))
to_chat(user, span_notice("The button panel is currently recharging."))
return
lastRTDtime = world.time
var/randomnum = rand(1,6)
switch(randomnum)
TIMER_COOLDOWN_START(src, COOLDOWN_CLOWNCAR_RANDOMNESS, dice_cooldown_time)
switch(rand(1,6))
if(1)
visible_message("<span class='danger'>[user] has pressed one of the colorful buttons on [src] and a special banana peel drops out of it.</span>")
visible_message(span_danger("[user] presses one of the colorful buttons on [src], and a special banana peel drops out of it."))
new /obj/item/grown/bananapeel/specialpeel(loc)
if(2)
visible_message("<span class='danger'>[user] has pressed one of the colorful buttons on [src] and unknown chemicals flood out of it.</span>")
var/datum/reagents/R = new/datum/reagents(300)
R.my_atom = src
R.add_reagent(get_random_reagent_id(), 100)
visible_message(span_danger("[user] presses one of the colorful buttons on [src], and unknown chemicals flood out of it."))
var/datum/reagents/randomchems = new/datum/reagents(300)
randomchems.my_atom = src
randomchems.add_reagent(get_random_reagent_id(), 100)
var/datum/effect_system/foam_spread/foam = new
foam.set_up(200, loc, R)
foam.set_up(200, loc, randomchems)
foam.start()
if(3)
visible_message("<span class='danger'>[user] has pressed one of the colorful buttons on [src] and the clown car turns on its singularity disguise system.</span>")
visible_message(span_danger("[user] presses one of the colorful buttons on [src], and the clown car turns on its singularity disguise system."))
icon = 'icons/obj/singularity.dmi'
icon_state = "singularity_s1"
addtimer(CALLBACK(src, .proc/ResetIcon), 100)
addtimer(CALLBACK(src, .proc/reset_icon), 10 SECONDS)
if(4)
visible_message("<span class='danger'>[user] has pressed one of the colorful buttons on [src] and the clown car spews out a cloud of laughing gas.</span>")
var/datum/reagents/R = new/datum/reagents(300)
R.my_atom = src
R.add_reagent(/datum/reagent/consumable/superlaughter, 50)
visible_message(span_danger("[user] presses one of the colorful buttons on [src], and the clown car spews out a cloud of laughing gas."))
var/datum/reagents/funnychems = new/datum/reagents(300)
funnychems.my_atom = src
funnychems.add_reagent(/datum/reagent/consumable/superlaughter, 50)
var/datum/effect_system/smoke_spread/chem/smoke = new()
smoke.set_up(R, 4)
smoke.set_up(funnychems, 4)
smoke.attach(src)
smoke.start()
if(5)
visible_message("<span class='danger'>[user] has pressed one of the colorful buttons on [src] and the clown car starts dropping an oil trail.</span>")
droppingoil = TRUE
addtimer(CALLBACK(src, .proc/StopDroppingOil), 30)
visible_message(span_danger("[user] presses one of the colorful buttons on [src], and the clown car starts dropping an oil trail."))
RegisterSignal(src, COMSIG_MOVABLE_MOVED, .proc/cover_in_oil)
addtimer(CALLBACK(src, .proc/stop_dropping_oil), 3 SECONDS)
if(6)
visible_message("<span class='danger'>[user] has pressed one of the colorful buttons on [src] and the clown car lets out a comedic toot.</span>")
visible_message(span_danger("[user] presses one of the colorful buttons on [src], and the clown car lets out a comedic toot."))
playsound(src, 'sound/vehicles/clowncar_fart.ogg', 100)
for(var/mob/living/L in orange(loc, 6))
L.emote("laughs")
for(var/mob/living/L in occupants)
for(var/mob/living/L as anything in occupants)
L.emote("laughs")
/obj/vehicle/sealed/car/clowncar/proc/ResetIcon()
///resets the icon and iconstate of the clowncar after it was set to singulo states
/obj/vehicle/sealed/car/clowncar/proc/reset_icon()
icon = initial(icon)
icon_state = initial(icon_state)
/obj/vehicle/sealed/car/clowncar/proc/StopDroppingOil()
droppingoil = FALSE
///Deploys oil when the clowncar moves in oil deploy mode
/obj/vehicle/sealed/car/clowncar/proc/cover_in_oil()
SIGNAL_HANDLER
new /obj/effect/decal/cleanable/oil/slippery(loc)
///Stops dropping oil after the time has run up
/obj/vehicle/sealed/car/clowncar/proc/stop_dropping_oil()
UnregisterSignal(src, COMSIG_MOVABLE_MOVED)
///Toggles the on and off state of the clown cannon that shoots random kidnapped people
/obj/vehicle/sealed/car/clowncar/proc/toggle_cannon(mob/user)
if(cannonmode == CLOWN_CANNON_BUSY)
to_chat(user, span_notice("Please wait for the vehicle to finish its current action first."))
return
if(cannonmode) //canon active, deactivate
flick("clowncar_fromfire", src)
icon_state = "clowncar"
addtimer(CALLBACK(src, .proc/deactivate_cannon), 2 SECONDS)
playsound(src, 'sound/vehicles/clowncar_cannonmode2.ogg', 75)
visible_message(span_danger("The [src] starts going back into mobile mode."))
else
canmove = FALSE //anchor and activate canon
flick("clowncar_tofire", src)
icon_state = "clowncar_fire"
visible_message(span_danger("The [src] opens up and reveals a large cannon."))
addtimer(CALLBACK(src, .proc/activate_cannon), 2 SECONDS)
playsound(src, 'sound/vehicles/clowncar_cannonmode1.ogg', 75)
cannonmode = CLOWN_CANNON_BUSY
///Finalizes canon activation
/obj/vehicle/sealed/car/clowncar/proc/activate_cannon()
// mouse_pointer = 'icons/effects/mouse_pointers/mecha_mouse.dmi'
cannonmode = CLOWN_CANNON_READY
for(var/mob/living/driver as anything in return_controllers_with_flag(VEHICLE_CONTROL_DRIVE))
driver.update_mouse_pointer()
///Finalizes canon deactivation
/obj/vehicle/sealed/car/clowncar/proc/deactivate_cannon()
canmove = TRUE
// mouse_pointer = null
cannonmode = CLOWN_CANNON_INACTIVE
for(var/mob/living/driver as anything in return_controllers_with_flag(VEHICLE_CONTROL_DRIVE))
driver.update_mouse_pointer()
///Fires the cannon where the user clicks
/obj/vehicle/sealed/car/clowncar/proc/fire_cannon_at(mob/user, atom/A, params)
SIGNAL_HANDLER
if(cannonmode != CLOWN_CANNON_READY || !length(return_controllers_with_flag(VEHICLE_CONTROL_KIDNAPPED)))
return NONE
var/mob/living/unlucky_sod = pick(return_controllers_with_flag(VEHICLE_CONTROL_KIDNAPPED))
mob_exit(unlucky_sod, TRUE)
flick("clowncar_recoil", src)
playsound(src, pick('sound/vehicles/carcannon1.ogg', 'sound/vehicles/carcannon2.ogg', 'sound/vehicles/carcannon3.ogg'), 75)
unlucky_sod.throw_at(A, 10, 2)
log_combat(user, unlucky_sod, "fired", src, "towards [A]") //this doesn't catch if the mob hits something between the car and the target
return COMSIG_MOB_CANCEL_CLICKON
///Increments the thanks counter every time someone thats been kidnapped thanks the driver
/obj/vehicle/sealed/car/clowncar/proc/increment_thanks_counter()
thankscount++
if(thankscount < 100)
return
for(var/mob/busdriver as anything in return_drivers())
busdriver.client.give_award(/datum/award/achievement/misc/the_best_driver, busdriver)
/obj/vehicle/sealed/car/clowncar/twitch_plays
key_type = null
@@ -144,12 +244,10 @@
/obj/vehicle/sealed/car/clowncar/twitch_plays/Initialize()
. = ..()
AddComponent(/datum/component/twitch_plays/simple_movement)
START_PROCESSING(SSfastprocess, src)
GLOB.poi_list |= src
notify_ghosts("Twitch Plays: Clown Car")
/obj/vehicle/sealed/car/clowncar/twitch_plays/Destroy()
STOP_PROCESSING(SSfastprocess, src)
GLOB.poi_list -= src
return ..()
@@ -158,3 +256,4 @@
if(!dir)
return
driver_move(null, dir)
..()

View File

@@ -126,44 +126,70 @@
desc = "Honk your classy horn."
button_icon_state = "car_horn"
var/hornsound = 'sound/items/carhorn.ogg'
var/last_honk_time
/datum/action/vehicle/sealed/horn/Trigger()
if(world.time - last_honk_time > 20)
vehicle_entered_target.visible_message("<span class='danger'>[vehicle_entered_target] loudly honks</span>")
to_chat(owner, "<span class='notice'>You press the vehicle's horn.</span>")
playsound(vehicle_entered_target, hornsound, 75)
last_honk_time = world.time
if(TIMER_COOLDOWN_CHECK(src, COOLDOWN_CAR_HONK))
return
TIMER_COOLDOWN_START(src, COOLDOWN_CAR_HONK, 2 SECONDS)
vehicle_entered_target.visible_message(span_danger("[vehicle_entered_target] loudly honks!"))
to_chat(owner, span_notice("You press [vehicle_entered_target]'s horn."))
if(istype(vehicle_target.inserted_key, /obj/item/bikehorn))
vehicle_target.inserted_key.attack_self(owner) //The bikehorn plays a sound instead
return
playsound(vehicle_entered_target, hornsound, 75)
/datum/action/vehicle/sealed/horn/clowncar/Trigger()
if(world.time - last_honk_time > 20)
vehicle_entered_target.visible_message("<span class='danger'>[vehicle_entered_target] loudly honks</span>")
to_chat(owner, "<span class='notice'>You press the vehicle's horn.</span>")
last_honk_time = world.time
if(vehicle_target.inserted_key)
vehicle_target.inserted_key.attack_self(owner) //The key plays a sound
else
playsound(vehicle_entered_target, hornsound, 75)
/datum/action/vehicle/sealed/DumpKidnappedMobs
name = "Dump kidnapped mobs"
/datum/action/vehicle/sealed/dump_kidnapped_mobs
name = "Dump Kidnapped Mobs"
desc = "Dump all objects and people in your car on the floor."
button_icon_state = "car_dump"
/datum/action/vehicle/sealed/DumpKidnappedMobs/Trigger()
vehicle_entered_target.visible_message("<span class='danger'>[vehicle_entered_target] starts dumping the people inside of it.</span>")
/datum/action/vehicle/sealed/dump_kidnapped_mobs/Trigger()
vehicle_entered_target.visible_message(span_danger("[vehicle_entered_target] starts dumping the people inside of it."))
vehicle_entered_target.DumpSpecificMobs(VEHICLE_CONTROL_KIDNAPPED)
/datum/action/vehicle/sealed/RollTheDice
name = "Press a colorful button"
/datum/action/vehicle/sealed/roll_the_dice
name = "Press Colorful Button"
desc = "Press one of those colorful buttons on your display panel!"
button_icon_state = "car_rtd"
/datum/action/vehicle/sealed/RollTheDice/Trigger()
if(istype(vehicle_entered_target, /obj/vehicle/sealed/car/clowncar))
var/obj/vehicle/sealed/car/clowncar/C = vehicle_entered_target
C.RollTheDice(owner)
/datum/action/vehicle/sealed/roll_the_dice/Trigger()
if(!istype(vehicle_entered_target, /obj/vehicle/sealed/car/clowncar))
return
var/obj/vehicle/sealed/car/clowncar/C = vehicle_entered_target
C.roll_the_dice(owner)
/datum/action/vehicle/sealed/cannon
name = "Toggle Siege Mode"
desc = "Destroy them with their own fodder!"
button_icon_state = "car_cannon"
/datum/action/vehicle/sealed/cannon/Trigger()
if(!istype(vehicle_entered_target, /obj/vehicle/sealed/car/clowncar))
return
var/obj/vehicle/sealed/car/clowncar/C = vehicle_entered_target
C.toggle_cannon(owner)
/datum/action/vehicle/sealed/thank
name = "Thank the Clown Car Driver"
desc = "They're just doing their job."
button_icon_state = "car_thanktheclown"
COOLDOWN_DECLARE(thank_time_cooldown)
/datum/action/vehicle/sealed/thank/Trigger()
if(!istype(vehicle_entered_target, /obj/vehicle/sealed/car/clowncar))
return
if(!COOLDOWN_FINISHED(src, thank_time_cooldown))
return
COOLDOWN_START(src, thank_time_cooldown, 6 SECONDS)
var/obj/vehicle/sealed/car/clowncar/clown_car = vehicle_entered_target
var/mob/living/carbon/human/clown = pick(clown_car.return_drivers())
if(!clown)
return
owner.say("Thank you for the fun ride, [clown.name]!")
clown_car.increment_thanks_counter()
/datum/action/vehicle/ridden/scooter/skateboard/ollie
@@ -197,7 +223,9 @@
L.Move(landing_turf, vehicle_target.dir)
passtable_off(L, VEHICLE_TRAIT)
V.pass_flags &= ~PASSTABLE
if(locate(/obj/structure/table) in V.loc.contents)
if((locate(/obj/structure/table) in V.loc.contents) || (locate(/obj/structure/fluff/railing) in V.loc.contents))
if(locate(/obj/structure/fluff/railing) in V.loc.contents)
L.client.give_award(/datum/award/achievement/misc/tram_surfer, L)
V.grinding = TRUE
V.icon_state = "[V.board_icon]-grind"
addtimer(CALLBACK(V, /obj/vehicle/ridden/scooter/skateboard/.proc/grind), 2)

View File

@@ -15,9 +15,9 @@
/obj/item/clothing/glasses/monocle = 3,
/obj/item/clothing/suit/jacket = 4,
/obj/item/clothing/suit/jacket/flannel = 4,
/obj/item/clothing/suit/jacket/flannel/red = 4,
/obj/item/clothing/suit/jacket/flannel/aqua = 4,
/obj/item/clothing/suit/jacket/flannel/brown = 4,
/obj/item/clothing/suit/toggle/jacket/flannel/red = 4,
/obj/item/clothing/suit/toggle/jacket/flannel/aqua = 4,
/obj/item/clothing/suit/toggle/jacket/flannel/brown = 4,
/obj/item/clothing/suit/jacket/puffer/vest = 4,
/obj/item/clothing/suit/jacket/puffer = 4,
/obj/item/clothing/suit/hooded/cloak/david = 4,
@@ -219,7 +219,17 @@
/obj/item/clothing/under/misc/corporateuniform = 5,
/obj/item/clothing/suit/hooded/wintercoat/polychromic = 5,
/obj/item/clothing/suit/toggle/wbreakpoly/polychromic = 5,
/obj/item/clothing/shoes/sneakers/poly/polychromic = 10)
/obj/item/clothing/shoes/sneakers/poly/polychromic = 10,
/obj/item/clothing/suit/toggle/jacket/fancytrench = 4,
/obj/item/clothing/suit/toggle/jacket/greenjacket = 4,
/obj/item/clothing/suit/jacket/gentlecoat = 4,
/obj/item/clothing/suit/jacket/gothicshirtcross = 4,
/obj/item/clothing/suit/jacket/gothicshirt = 4,
/obj/item/clothing/suit/jacket/gothiccoat = 4,
/obj/item/clothing/suit/jacket/heartcoat = 4,
/obj/item/clothing/suit/jacket/purplehoodie = 4,
/obj/item/clothing/suit/jacket/bluehoodie = 4,
/obj/item/clothing/suit/toggle/jacket/whitehoodie = 4)
refill_canister = /obj/item/vending_refill/clothing
default_price = PRICE_CHEAP
extra_price = PRICE_BELOW_NORMAL

View File

@@ -10,7 +10,9 @@
/obj/item/toy/cards/deck/unum = 3,
/obj/item/cardpack/series_one = 10,
/obj/item/dyespray=3,
/obj/item/tcgcard_binder = 5)
/obj/item/tcgcard_binder = 5,
/obj/item/canvas = 3,
/obj/item/toy/crayon/spraycan = 3)
contraband = list(/obj/item/dice/fudge = 9)
premium = list(/obj/item/melee/skateboard/pro = 3,
/obj/item/melee/skateboard/hoverboard = 1)