/
githubmirror
/
vgstation13
Обзор
Документация
Войти
/
githubmirror
/
vgstation13
Код
Запросы
0
Пакеты
0
Релизы
0
Аналитика
Безопасность
Bleeding-Edge
code/game/objects/objs.dm
960 строк
34 KB
SECBATON GRIFFON
Makes pulse demons show up on T-ray scanners (#39273)
17 июл 2026, 14:13
Не верифицирован
17 июл 2026, 14:13
f973b57
Код
Авторство
О чём код?
//reagents that should adminwarn upon transfer var/global/list/reagents_to_log = list(FUEL, PLASMA, PACID, SACID, AMUTATIONTOXIN, MINDBREAKER, SPIRITBREAKER, CYANIDE, IMPEDREZENE, LUBE, CHEFSPECIAL, AMANITIN) //dangerous reagents that should always be logged upon transfer no matter what var/global/list/reagents_to_always_log = list(AMUTATIONTOXIN, CYANIDE, CHEFSPECIAL, AMANITIN) /obj var/origin_tech = null //Used by R&D to determine what research bonuses it grants. var/reliability = 100 //Used by SOME devices to determine how reliable they are. var/crit_fail = 0 animate_movement = 2 var/throwforce = 1 var/siemens_coefficient = 0 // for electrical admittance/conductance (electrocution checks and shit) - 0 is not conductive, 1 is conductive - this is a range, not binary var/sharpness = 0 //not a binary - rough guide is 0.8 cutting, 1 cutting well, 1.2 specifically sharp (knives, etc) 1.5 really sharp (scalpels, e-weapons) var/sharpness_flags = 0 //Describe in which way this thing is sharp. Shouldn't sharpness be exclusive to obj/item? var/heat_production = 0 var/source_temperature = 0 var/price = 0 var/in_use = 0 // If we have a user using us, this will be set on. We will check if the user has stopped using us, and thus stop updating and LAGGING EVERYTHING! var/damtype = "brute" var/force = 0 var/w_class //Should we alert about reagents that should be logged? var/log_reagents = 1 var/list/mob/_using // All mobs dicking with us. // Shit for mechanics. (MECH_*) var/mech_flags=0 plane = OBJ_PLANE var/quality = B_AVERAGE //What level of quality this object is. var/datum/material/material_type //What material this thing is made out of var/sheet_type = /obj/item/stack/sheet/metal var/sheet_amt = 1 var/can_take_pai = FALSE var/obj/item/device/paicard/integratedpai = null var/datum/delay_controller/pAImove_delayer var/pAImovement_delay = 0 //Can we wrench/weld this to a turf with a dense /obj on it? var/can_affix_to_dense_turf=0 var/list/alphas_obj = list() var/impactsound var/current_glue_state = GLUE_STATE_NONE var/last_glue_application = 0 //Does this item have slimes installed? Bitflag for each type. var/has_slimes = 0 var/slimeadd_message = "You add the slime extract to SRCTAG" var/slimeadd_success_message var/slimes_accepted = 0 var/on_armory_manifest = FALSE // Does this get included in the armory manifest paper? var/holds_armory_items = FALSE // Does this check inside the object for stuff to include? //Cooking stuff: var/is_cooktop //If true, the object can be used in conjunction with a cooking vessel, eg. a frying pan, to cook food. var/obj/item/weapon/reagent_containers/pan/cookvessel //The vessel being used to cook food in. If generalized out to other types of vessels, make sure to also generalize the frying pan's cook_start(), etc. as well. var/verb_rotates = FALSE var/alt_click_rotates = FALSE var/ghost_can_rotate = FALSE var/rotates_anchored = FALSE var/rotate_type = null /obj/New() ..() if(breakable_flags) breakable_init() if(is_cooktop) add_component(/datum/component/cooktop) if(!thermal_mass) switch(w_class) if(W_CLASS_TINY, W_CLASS_SMALL) thermal_mass = 0.1 if(W_CLASS_MEDIUM) thermal_mass = 1.0 if(W_CLASS_LARGE) thermal_mass = 5.0 if(W_CLASS_HUGE) thermal_mass = 20.0 if(W_CLASS_GIANT) thermal_mass = 50.0 if(thermal_mass) initial_thermal_mass = thermal_mass if(flammable) var/turf/simulated/T = get_turf(src) if(istype(T)) T.zone?.burnable_atoms |= src if(verb_rotates) verbs += /obj/proc/rotate_cw verbs += /obj/proc/rotate_ccw //More cooking stuff: /obj/proc/can_cook() //Returns true if object is currently in a state that would allow for food to be cooked on it (eg. the grill is currently powered on). Can (and generally should) be overriden to check for more specific conditions. if(is_cooktop) return TRUE return FALSE /obj/proc/can_receive_cookvessel() //Returns true if object is currently in a state that would allow for a cooking vessel to be placed on or in it (eg. there's not already something being grilled). Can (and generally should) be overriden to check for more specific conditions. //Doesn't need to check for there already being a cooking vessel, as that is already handled separately by the cooktop component. return TRUE /obj/proc/on_cook_start() //Anything that needs to be done when we start cooking something. return /obj/proc/on_cook_stop() //Anything that needs to be done when we stop cooking something. return /obj/proc/render_cookvessel(offset_x, offset_y) //Called whenever we want to visibly render the cooking vessel. if(cookvessel) var/image/cookvesselimage = image(cookvessel) cookvesselimage.pixel_x = offset_x cookvesselimage.pixel_y = offset_y overlays += cookvesselimage adjust_particles(PVAR_POSITION, list(offset_x,offset_y)) else adjust_particles(PVAR_POSITION, 0) /obj/proc/cook_temperature() //Returns the temperature the object cooks at. return COOKTEMP_DEFAULT /obj/proc/cook_energy() //Returns the energy transferred to the reagents in the cooking vessel per process() tick of the cooking vessel. Cooking vessels use the fast objects subsystem. return 500 //Half that of fire_act(). /obj/proc/generate_available_recipes(flags = COOKABLE_WITH_ALL) var/list/recipes = list() for(var/type in (typesof(/datum/recipe) - /datum/recipe)) var/datum/recipe/thisrecipe = new type if((thisrecipe.cookable_with & flags) && ispath(thisrecipe.result)) //Check that the recipe is cookable with the given method, and also that the recipe isn't a base type with no result. recipes += thisrecipe return recipes // Whether this object can appear in holomaps /obj/proc/supports_holomap() return FALSE /obj/proc/add_self_to_holomap() var/turf/T = loc if(istype(T) && ticker && ticker.current_state != GAME_STATE_PLAYING) T.add_holomap(src) /obj/Destroy() for(var/mob/user in _using) user.unset_machine() if(src in processing_objects) processing_objects -= src if(integratedpai) QDEL_NULL(integratedpai) material_type = null //Don't qdel, they're held globally if(associated_forward) associated_forward = null ..() /obj/item/proc/is_used_on(obj/O, mob/user) /obj/proc/blocks_doors(var/obj/machinery/door/D) return 0 /obj/proc/install_pai(obj/item/device/paicard/P) if(!P || !istype(P)) return 0 P.forceMove(src) integratedpai = P verbs += /obj/proc/remove_pai pAImove_delayer = new(1, ARBITRARILY_LARGE_NUMBER) /obj/attackby(obj/item/weapon/W, mob/user) INVOKE_EVENT(src, /event/attackby, "attacker" = user, "item" = W) if(handle_item_attack(W, user)) return if(emag_check(W,user)) . = 1 if(can_take_pai && istype(W, /obj/item/device/paicard)) if(integratedpai) to_chat(user, "<span class = 'notice'>There's already a Personal AI inserted.</span>") return if(user.drop_item(W)) to_chat(user, "You insert \the [W] into a slot in \the [src].") install_pai(W) state_controls_pai(W) playsound(src, 'sound/misc/cartridge_in.ogg', 25) if(W) if(W.material_type) W.material_type.on_use(W, src, user) /obj/proc/state_controls_pai(obj/item/device/paicard/P) //text the pAI receives when is inserted into something. EXAMPLE: to_chat(P.pai, "Welcome to your new body") if(P.pai) return 1 return 0 /obj/proc/attack_integrated_pai(mob/living/silicon/pai/user) //called when integrated pAI clicks on the object, or uses the attack_self() hotkey return /obj/proc/swapkey_integrated_pai(mob/living/silicon/pai/user) //called when integrated pAI uses the swap_hand() hotkey return /obj/proc/throwkey_integrated_pai(mob/living/silicon/pai/user) //called when integrated pAI uses the toggle_throw_mode() hotkey return /obj/proc/dropkey_integrated_pai(mob/living/silicon/pai/user) //called when integrated pAI uses the drop hotkey return /obj/proc/equipkey_integrated_pai(mob/living/silicon/pai/user) //called when integrated pAI uses the equip hotkey return /obj/proc/intentright_integrated_pai(mob/living/silicon/pai/user) //called when integrated pAI uses the cycle-intent-right hotkey return /obj/proc/intentleft_integrated_pai(mob/living/silicon/pai/user) //called when integrated pAI uses the cycle-intent-left hotkey return /obj/proc/intenthelp_integrated_pai(mob/living/silicon/pai/user) //called when integrated pAI uses the help intent hotkey return /obj/proc/intentdisarm_integrated_pai(mob/living/silicon/pai/user) //called when integrated pAI uses the disarm intent hotkey return /obj/proc/intentgrab_integrated_pai(mob/living/silicon/pai/user) //called when integrated pAI uses the grab intent hotkey return /obj/proc/intenthurt_integrated_pai(mob/living/silicon/pai/user) //called when integrated pAI uses the hurt intent hotkey return /obj/proc/pAImove(mob/living/user, dir) //called when integrated pAI attempts to move if(pAImove_delayer.blocked()) user.last_movement=world.time return 0 else delayNextpAIMove(getpAIMovementDelay()) if (user.client.prefs.get_pref(/datum/preference_setting/toggle/stumble) && ((world.time - user.last_movement) > 5) && getpAIMovementDelay() < 2) delayNextpAIMove(3) //if set, delays the second step when a mob starts moving to attempt to make precise high ping movement easier user.last_movement=world.time return 1 /obj/proc/getpAIMovementDelay() return pAImovement_delay /obj/proc/delayNextpAIMove(var/delay, var/additive=0) pAImove_delayer.delayNext(delay,additive) /obj/proc/on_integrated_pai_click(mob/living/silicon/pai/user, var/atom/A) if(istype(A,/obj/machinery)||(istype(A,/mob)&&user.secHUD)) A.attack_pai(user) /obj/proc/remove_pai() set name = "Remove pAI" set category = "Object" set src in range(1) var/mob/M = usr if(!M.Adjacent(src)) return if(!M.dexterity_check()) to_chat(usr, "You don't have the dexterity to do this!") return if(M.incapacitated()) to_chat(M, "You can't do that while you're incapacitated!") return to_chat(M, "You eject \the [integratedpai] from \the [src].") M.put_in_hands(eject_integratedpai_if_present()) playsound(src, 'sound/misc/cartridge_out.ogg', 25) /obj/proc/eject_integratedpai_if_present() if(integratedpai) integratedpai.forceMove(get_turf(src)) verbs -= /obj/proc/remove_pai var/obj/item/device/paicard/P = integratedpai integratedpai = null QDEL_NULL(pAImove_delayer) return P return 0 /obj/AltClick(mob/user) if(alt_click_rotates & Adjacent(user)) rotate_ccw() return ..() /obj/proc/rotate_cw() set name = "Rotate Clockwise" set category = "Object" set src in oview(1) rotate(270) return 1 /obj/proc/rotate_ccw() set name = "Rotate Counter Clockwise" set category = "Object" set src in oview(1) rotate(90) return 1 /obj/proc/rotate(var/angle = 90) if(ghost_can_rotate && isobserver(usr)) var/mob/dead/observer/ghost = usr if(ghost.last_obj_spin <= world.time - 5) //do not spam this investigation_log(I_GHOST, "|| was rotated by [key_name(ghost)][ghost.locked_to ? ", who was haunting [ghost.locked_to]" : ""]") ghost.last_obj_spin = world.time else if (usr.incapacitated()) to_chat(usr, "<span class='warning'>You cannot rotate this while incapacitated!</span>") return 0 if(!rotates_anchored && anchored) var/turf/T = loc if(T) for(var/obj/O in T) var/rotated_type = rotate_type || src.type if(istype(O,rotated_type) && !O.anchored && O.dir == src.dir) O.rotate(angle) return 0 to_chat(usr, "<span class='warning'>\The [src] is fastened to the floor, therefore you can't rotate it!</span>") return 0 change_dir(turn(dir, angle)) return 1 /obj/recycle(var/datum/materials/rec) if(..()) return 1 return w_type /* /obj/melt() var/obj/effect/decal/slag/slag=locate(/obj/effect/decal/slag) in get_turf(src) if(!slag) slag = new(get_turf(src)) slag.slaggify(src) */ /obj/proc/is_conductor(var/siemens_min = 0.5) if(src.siemens_coefficient >= siemens_min) return 1 return /obj/clean_act(var/cleanliness) ..() if (cleanliness >= CLEANLINESS_WATER) unglue() /obj/proc/cultify() qdel(src) /obj/proc/clockworkify() return /obj/map_element_rotate(var/angle) ..() if(req_access_dir) req_access_dir = turn(req_access_dir, -angle) /obj/proc/wrenchable() return 0 /obj/proc/can_wrench_shuttle() return 0 /obj/proc/is_sharp() return sharpness /obj/is_hot() //This returns the temperature of the object if possible return source_temperature /obj/thermal_energy_transfer() if(is_hot()) return heat_production return 0 /obj/proc/process() set waitfor = FALSE processing_objects.Remove(src) //At some point, this proc should be changed to work like remove_air() below does. //However, this would likely cause problems, such as CO2 buildup in mechs and spacepods, so I'm not doing it right now. /obj/assume_air(datum/gas_mixture/giver) if(loc) return loc.assume_air(giver) else return null /obj/remove_air(amount) var/datum/gas_mixture/my_air = return_air() return my_air?.remove(amount) /obj/return_air() if(loc) return loc.return_air() else return null /obj/proc/handle_internal_lifeform(mob/lifeform_inside_me, breath_vol) if(breath_vol > 0) var/datum/gas_mixture/G = return_air() return G.remove_volume(breath_vol) else return null /obj/proc/updateUsrDialog() if(in_use) var/is_in_use = 0 if(_using && _using.len) var/list/nearby = viewers(1, src) + loc //List of nearby things includes the location - allows you to call this proc on items and such for(var/mob/M in _using) // Only check things actually messing with us. if (!M || !M.client) _using.Remove(M) continue // AIs/Robots can do shit from afar. if (isAI(M) || isrobot(M) || isAdminGhost(M)) is_in_use = 1 src.attack_ai(M) else if(ispulsedemon(M)) is_in_use = 1 src.attack_pulsedemon(M) else if(!(M in nearby)) // NOT NEARBY // check for TK users if(M.mutations && M.mutations.len) if(M_TK in M.mutations) is_in_use = 1 src.attack_hand(M, TRUE) // The second param is to make sure brain damage on the user doesn't cause the UI to not update but the action to still happen. else // Remove. _using.Remove(M) continue else // EVERYTHING FROM HERE DOWN MUST BE NEARBY is_in_use = 1 attack_hand(M, TRUE) in_use = is_in_use /obj/item/updateUsrDialog() if(in_use) var/is_in_use = 0 if(_using && usr) _using |= usr if(_using && _using.len) for(var/mob/M in _using) // Only check things actually messing with us. if (!M || !M.client || !in_range(loc,M)) // NOT ON MOB _using.Remove(M) continue is_in_use = 1 src.attack_self(M) // check for TK users in_use = is_in_use /obj/proc/updateDialog() // Check that people are actually using the machine. If not, don't update anymore. if(in_use) var/list/nearby = viewers(1, src) var/is_in_use = 0 for(var/mob/M in _using) // Only check things actually messing with us. // Not actually using the fucking thing? if (!M || !M.client || M.machine != src) _using.Remove(M) continue // Not robot or AI, not nearby and not pulse demon? if(!isAI(M) && !isrobot(M) && !(M in nearby) && !ispulsedemon(M)) _using.Remove(M) continue is_in_use = 1 src.interact(M) in_use = is_in_use /obj/proc/interact(mob/user) return /obj/suicide_act(var/mob/living/user) if (is_hot()) user.visible_message("<span class='danger'>[user] is immolating \himself on \the [src]! It looks like \he's trying to commit suicide.</span>") user.ignite() return SUICIDE_ACT_FIRELOSS else if (sharpness >= 1) user.visible_message("<span class='danger'>[user] impales himself on \the [src]! It looks like \he's trying to commit suicide.</span>") return SUICIDE_ACT_BRUTELOSS else if (force >= 10) if (prob(50)) playsound(user, 'sound/items/trayhit1.ogg', 50, 1) else playsound(user, 'sound/items/trayhit2.ogg', 50, 1) user.visible_message("<span class='danger'>[user] strikes his head on \the [src]! It looks like \he's trying to commit suicide.</span>") return SUICIDE_ACT_BRUTELOSS /obj/ignite() if(..()) remove_particles(PS_SMOKE) /obj/singularity_act() if(flags & INVULNERABLE) return ex_act(1) if(src) qdel(src) return 2 /obj/shuttle_act(datum/shuttle/S) return qdel(src) /obj/slime_act(primarytype, mob/user) if(has_slimes & primarytype) to_chat(user, "\the [src] already has this kind of slime extract attached.") return FALSE has_slimes |= primarytype slimeadd_message = replacetext(slimeadd_message,"SRCTAG","\the [src]") to_chat(user, "[slimeadd_message][slimeadd_success_message && (slimes_accepted & primarytype) ? ". [slimeadd_success_message]" : ""].") return TRUE /obj/singularity_pull(S, current_size, repel = FALSE) INVOKE_EVENT(src, /event/before_move) if(anchored) if(current_size >= STAGE_FIVE) anchored = 0 if(!repel) step_towards(src, S) else step_away(src, S) else if(!repel) step_towards(src, S) else step_away(src, S) INVOKE_EVENT(src, /event/after_move) /obj/proc/multitool_menu(var/mob/user,var/obj/item/device/multitool/P) return "<b>NO MULTITOOL_MENU!</b>" /obj/proc/shouldReInitOnMultitoolLink(var/mob/user, var/obj/buffer, var/list/context) return FALSE /mob/proc/unset_machine() if(machine) if(machine._using) machine._using -= src if(!machine._using.len) machine._using = null machine = null /mob/proc/set_machine(const/obj/O) unset_machine() if(istype(O)) machine = O if(!machine._using) machine._using = new machine._using += src machine.in_use = 1 /** Returns 1 or 0 depending on whether the machine can be affixed to this position. * Used to determine whether other density=1 things are on this tile. * @param user Tool user * @return bool Can affix here */ /obj/proc/canAffixHere(var/mob/user) if(density==0 || can_affix_to_dense_turf) return TRUE// Non-dense things just don't care. Same with can_affix_to_dense_turf=TRUE objects. for(var/obj/other in loc) //ensure multiple things aren't anchored in one place if(other.anchored == 1 && other.density == 1 && density && !anchored && !(other.flow_flags & ON_BORDER) && !(istype(other,/obj/structure/table))) to_chat(user, "\The [other] is already anchored in this location.") return FALSE // NOPE return TRUE /** Anchors shit to the deck via wrench. * @param user The mob doing the wrenching * @param time_to_wrench The time to complete the wrenchening * @returns TRUE on success, FALSE on fail */ /obj/proc/wrenchAnchor(var/mob/user, var/obj/item/I, var/time_to_wrench = 3 SECONDS) //proc to wrench an object that can be secured if(!canAffixHere(user)) return FALSE if(!anchored) if(!istype(src.loc, /turf/simulated/floor)) //Prevent from anchoring shit to shuttles / space if(isshuttleturf(src.loc) && !can_wrench_shuttle()) //If on the shuttle and not wrenchable to shuttle to_chat(user, "<span class = 'notice'>You can't secure \the [src] to this!</span>") return FALSE if(istype(src.loc, /turf/space)) //if on a space tile to_chat(user, "<span class = 'notice'>You can't secure \the [src] to space!</span>") return FALSE user.visible_message( "[user] begins to [anchored ? "unbolt" : "bolt"] \the [src] [anchored ? "from" : "to" ] the floor.", "You begin to [anchored ? "unbolt" : "bolt"] \the [src] [anchored ? "from" : "to" ] the floor.") if(I) I.playtoolsound(loc, 50) if(do_after(user, src, time_to_wrench)) if(!canAffixHere(user)) return FALSE anchored = !anchored user.visible_message( "<span class='notice'>[user] [anchored ? "wrench" : "unwrench"]es \the [src] [anchored ? "in place" : "from its fixture"]</span>", "<span class='notice'>[bicon(src)] You [anchored ? "wrench" : "unwrench"] \the [src] [anchored ? "in place" : "from its fixture"].</span>", "<span class='notice'>You hear a ratchet.</span>") if(verb_rotates) if(anchored) verbs |= /obj/proc/rotate_cw verbs |= /obj/proc/rotate_ccw else verbs -= /obj/proc/rotate_cw verbs -= /obj/proc/rotate_ccw return TRUE return FALSE /obj/item/proc/updateSelfDialog() var/mob/M = src.loc if(istype(M) && M.client && M.machine == src) src.attack_self(M) /obj/proc/alter_health() return 1 /obj/proc/hide(h) return /** * Called when a mob inside this obj's contents logs out. */ /obj/proc/on_logout(var/mob/M) if(isobj(loc)) var/obj/location = loc location.on_logout(M) /** * Called when a mob inside this obj's contents logs in. */ /obj/proc/on_login(var/mob/M) if(isobj(loc)) var/obj/location = loc location.on_login(M) // Dummy to give items special techlist for the purposes of the Device Analyser, in case you'd ever need them to give them different tech levels depending on special checks. /obj/proc/give_tech_list() return null /obj/dissolvable() if (flags & INVULNERABLE) return FALSE else return PACID /obj/t_scanner_expose(ray_range) //don't reveal docking ports or spawns if(invisibility > 0 && invisibility < INVISIBILITY_OBSERVER || alpha < 255) var/old_invisibility = invisibility var/old_alpha = alpha invisibility = 0 alpha = 255 spawn(1 SECONDS) var/turf/U = loc if(istype(U) && U.intact) invisibility = old_invisibility alpha = old_alpha /obj/proc/clumsy_check(var/mob/living/user) if(istype(user)) if(isrobot(user)) var/mob/living/silicon/robot/R = user return HAS_MODULE_QUIRK(R, MODULE_IS_A_CLOWN) return (M_CLUMSY in user.mutations) || (user.reagents?.has_reagent(INCENSE_BANANA)) || (user.reagents?.has_reagent(HONKSERUM)) || arcanetampered return 0 //Proc that handles NPCs (gremlins) "tampering" with this object. //Return NPC_TAMPER_ACT_FORGET if there's no interaction (the NPC won't try to tamper with this again) //Return NPC_TAMPER_ACT_NOMSG if you don't want to create a visible_message /obj/proc/npc_tamper_act(mob/living/L) return NPC_TAMPER_ACT_FORGET /obj/actual_send_to_future(var/duration) var/turf/current_turf = get_turf(src) var/datum/current_loc = loc forceMove(null) ..() if(!current_loc.gcDestroyed) forceMove(current_loc) else forceMove(current_turf) /obj/send_to_past(var/duration) ..() var/static/list/resettable_vars = list( "sharpness", "integratedpai") reset_vars_after_duration(resettable_vars, duration) //Called when a mob in our locked atoms list kicks another object. Return 1 if successful, to abort the rest of the kicking action. /obj/proc/onBuckledUserKick(var/mob/living/user, var/atom/A) if(!anchored && !user.incapacitated() && user.has_limbs) //if you're buckled onto a non-anchored object (like office chairs) you harmlessly push yourself away with your legs spawn() //return 1 first thing var/movementdirection = turn(get_dir(src,A),180) if(user.get_strength() > 1) //hulk KICK! user.visible_message("<span class='danger'>[user] puts \his foot to \the [A] and kicks \himself away!</span>", \ "<span class='warning'>You put your foot to \the [A] and kick as hard as you can! [pick("RAAAAAAAARGH!", "HNNNNNNNNNGGGGGGH!", "GWAAAAAAAARRRHHH!", "NNNNNNNNGGGGGGGGHH!", "AAAAAAARRRGH!")]</span>") var/turf/T = get_edge_target_turf(src, movementdirection) src.throw_at(T, 8, 20, TRUE, 2) else user.visible_message("<span class='warning'>[user] kicks \himself away from \the [A].</span>", "<span class='notice'>You kick yourself away from \the [A]. Wee!</span>") for(var/i in list(2,2,3,3)) set_glide_size(DELAY2GLIDESIZE(i)) if(!step(src, movementdirection)) change_dir(turn(movementdirection, 180)) //stop, but don't turn around when hitting a wall break change_dir(turn(movementdirection, 180)) //face away from where we're going sleep(i) return 1 /obj/proc/make_invisible(var/source_define, var/time = 0, var/alpha_value = 1, var/invisibility_value = 0) //INVISIBILITY_MAXIMUM is a value of 100 for invisibility_value //alpha_value = 1 hides the sprite if(invisibility || alpha <= 1 || !source_define) return invisibility = invisibility_value alphas_obj[source_define] = alpha_value handle_alpha() if(ismob(loc)) var/mob/M = loc M.regenerate_icons() if(time > 0) spawn(time) make_visible(source_define) /obj/proc/make_visible(var/source_define) if(!invisibility && alpha == 255 || !source_define) return if(src && alphas_obj[source_define]) invisibility = 0 alphas_obj.Remove(source_define) handle_alpha() if(ismob(loc)) var/mob/M = loc M.regenerate_icons() /obj/proc/handle_alpha() //uses the lowest alpha on the mob if(alphas_obj.len < 1) alpha = 255 else sortTim(alphas_obj, /proc/cmp_numeric_asc,1) alpha = alphas_obj[alphas_obj[1]] /obj/proc/gen_quality(var/modifier = 0, var/min_quality = 0, var/datum/material/mat) var/material_mod = mat ? mat.quality_mod : material_type ? material_type.quality_mod : 1 var/surrounding_mod = 1 /* - Probably better we find a better way of checking the quality of a room, like an area-level variable for room quality, and cleanliness var/turf/T = get_turf(src) for(var/dir in alldirs) for(var/obj/I in get_step(T, dir)) if(I.quality > NORMAL || I.quality < NORMAL) surrounding_mod *= I.quality/rand(1,3) */ var/initial_quality = round(((rand(1,3)*surrounding_mod)*material_mod)+modifier) quality = clamp(initial_quality, B_AWFUL>min_quality?B_AWFUL:min_quality, B_LEGENDARY) var/processed_name = lowertext(mat? mat.processed_name : material_type.processed_name) var/to_icon_state = "[initial(icon_state)]_[processed_name]_[quality]" if(has_icon(icon, to_icon_state)) icon_state = to_icon_state /obj/proc/gen_description(mob/user) var/material_mod = quality-B_GOOD>1 ? quality-B_GOOD : 0 var/additional_description if(material_mod) additional_description = "On \the [src] is a carving, it depicts:\n" var/list/characters = list() for(var/i = 1 to material_mod) var/add_character if(prob(50)) //We're gonna use an atom var/atom/AM = pick(existing_typesof(/mob/living/simple_animal)) add_character = initial(AM.name) else add_character = pick("captain","clown","mime","\improper CMO","cargo technician","medical doctor","[user ? user : "stranger"]","octopus","changeling","\improper Nuclear Operative", "[pick("greyshirt", "greytide", "assistant")]", "xenomorph","catbeast","[user && user.mind && user.mind.heard_before.len ? pick(user.mind.heard_before) : "strange thing"]","Central Command","\improper Ian","[ticker.Bible_deity_name]","Nar-Sie","\improper Poly the Parrot","\improper Wizard","vox") characters |= add_character additional_description += "[i == material_mod ? " & a " : "[i > 1 ? ", a ": " A "]"][add_character]" additional_description += ". They are in \the [pick("captains office","Space","mining outpost","vox outpost","a space station","[station_name()]","bar","kitchen","library","Science","void","Bluespace","Hell","Central Command")]" if(material_mod > 2) additional_description += ". They are [pick("[pick("fighting","robusting","attacking","beating up", "abusing")] [pick("each other", pick(characters))]","playing cards","firing lasers at [pick("something",pick(characters))]","crying","laughing","blank faced","screaming","cooking [pick("something", pick(characters))]", "eating [pick("something", pick(characters))]")]. " if(characters.len > 1) for(var/i in characters) additional_description += "\The [i] is [pick("laughing","crying","screaming","naked","very naked","angry","jovial","manical","melting","fading away","making a plaintive gesture")]. " additional_description += "The scene gives off a feeling of [pick("unease","empathy","fear","malice","dread","happiness","strangeness","insanity","drol")]. " additional_description += "It is accented in hues of [pick("red","orange","yellow","green","blue","indigo","violet","white","black","cinnamon")]. " if(additional_description) desc = "[initial(desc)] \n [additional_description]" /obj/proc/dorfify(var/datum/material/mat, var/additional_quality, var/min_quality = 0) if(mat) /*var/icon/original = icon(icon, icon_state) Icon operations keep making mustard gas if(mat.color) original.ColorTone(mat.color) var/obj/item/I = src if(istype(I)) var/icon/t_state for(var/hand in list("left_hand", "right_hand")) t_state = icon(I.inhand_states[hand], I.item_state) t_state.ColorTone(mat.color) I.inhand_states[hand] = t_state else if(mat.color_matrix) color = mat.color_matrix icon = original*/ alpha = mat.alpha material_type = mat sheet_type = mat.sheettype gen_quality(additional_quality, min_quality) if(quality > B_SUPERIOR) gen_description() if(material_type) if(sharpness_flags && sharpness) force = initial(force)*(material_type.sharpness_mod*(quality/B_AVERAGE)) throwforce = initial(throwforce)*(material_type.sharpness_mod*(quality/B_AVERAGE)) sharpness = initial(sharpness)*(material_type.sharpness_mod*(quality/B_AVERAGE)) else force = initial(force)*(material_type.brunt_damage_mod*(quality/B_AVERAGE)) throwforce = initial(throwforce)*(material_type.brunt_damage_mod*(quality/B_AVERAGE)) if(!findtext(lowertext(name), lowertext(material_type.name))) name = "[quality == B_AVERAGE ? "": "[lowertext(qualityByString[quality])] "][lowertext(mat.name)] [name]" /obj/proc/check_uplink_validity() return TRUE //Return true if thrown object misses /obj/PreImpact(atom/movable/A, speed) if(flow_flags & ON_BORDER) //If the object should hit this, it will just by normal collision detection. return ..() if(density && !throwpass) return FALSE return TRUE /obj/proc/FeetStab(mob/living/AM,var/soundplay = 'sound/effects/glass_step.ogg',var/damage = 5,var/knockdown = 3) if(istype(AM)) if(AM.locked_to) //Mob is locked to something, so it's not actually stepping on the glass playsound(src, soundplay, 50, 1) return if(AM.flying) return else //Stepping on the glass playsound(src, soundplay, 50, 1) if(ishuman(AM)) var/mob/living/carbon/human/H = AM var/danger = FALSE var/datum/organ/external/foot = H.has_vulnerable_foot() if(foot) danger = TRUE if(!H.lying && H.feels_pain()) H.Knockdown(knockdown) H.Stun(knockdown) if(foot.take_damage(damage, 0)) H.UpdateDamageIcon() H.updatehealth() to_chat(AM, "<span class='[danger ? "danger" : "notice"]'>You step in \the [src]!</span>") /obj/proc/post_ruin_load() return /** * This proc is used for telling whether something can pass by this object in a given direction, for use by the pathfinding system. * * Trying to generate one long path across the station will call this proc on every single object on every single tile that we're seeing if we can move through, likely * multiple times per tile since we're likely checking if we can access said tile from multiple directions, so keep these as lightweight as possible. * * Arguments: * * ID- An ID card representing what access we have (and thus if we can open things like airlocks or windows to pass through them). The ID card's physical location does not matter, just the reference * * to_dir- What direction we're trying to move in, relevant for things like directional windows that only block movement in certain directions * * astar_caller- The movable we're checking pass flags for, if we're making any such checks **/ /obj/proc/CanAStarPass(obj/item/weapon/card/id/ID, to_dir, atom/movable/astar_caller) if(istype(astar_caller) && (astar_caller.pass_flags & pass_flags_self)) return TRUE . = !density /obj/proc/build_list_of_contents() //used by microwaves and frying pans var/dat = "" var/list/items_counts = new var/list/items_measures = new var/list/items_measures_p = new for (var/obj/O in contents) var/display_name = O.name if (istype(O,/obj/item/weapon/reagent_containers/food/snacks/meat)) //any meat items_measures[display_name] = "slab of meat" items_measures_p[display_name] = "slabs of meat" if (istype(O,/obj/item/weapon/reagent_containers/food/snacks/meat/carpmeat)) items_measures[display_name] = "fillet of fish" items_measures_p[display_name] = "fillets of fish" if (istype(O,/obj/item/weapon/reagent_containers/food/snacks/egg)) items_measures[display_name] = "egg" items_measures_p[display_name] = "eggs" if (istype(O,/obj/item/weapon/reagent_containers/food/snacks/tofu)) items_measures[display_name] = "tofu chunk" items_measures_p[display_name] = "tofu chunks" if (istype(O,/obj/item/weapon/reagent_containers/food/snacks/donkpocket)) display_name = "Turnovers" items_measures[display_name] = "turnover" items_measures_p[display_name] = "turnovers" if (istype(O,/obj/item/weapon/reagent_containers/food/snacks/grown/soybeans)) items_measures[display_name] = "soybean" items_measures_p[display_name] = "soybeans" if (istype(O,/obj/item/weapon/reagent_containers/food/snacks/grown/grapes)) display_name = "Grapes" items_measures[display_name] = "bunch of grapes" items_measures_p[display_name] = "bunches of grapes" if (istype(O,/obj/item/weapon/reagent_containers/food/snacks/grown/greengrapes)) display_name = "Green Grapes" items_measures[display_name] = "bunch of green grapes" items_measures_p[display_name] = "bunches of green grapes" if (istype(O,/obj/item/weapon/kitchen/utensil)) //any spoons, forks, knives, etc items_measures[display_name] = "utensil" items_measures_p[display_name] = "utensils" items_counts[display_name]++ for (var/O in items_counts) var/N = items_counts[O] if (!(O in items_measures)) dat += {"<B>[capitalize(O)]:</B> [N] [lowertext(O)]\s<BR>"} else if (N==1) dat += {"<B>[capitalize(O)]:</B> [N] [items_measures[O]]<BR>"} else dat += {"<B>[capitalize(O)]:</B> [N] [items_measures_p[O]]<BR>"} for (var/datum/reagent/R in reagents.reagent_list) var/display_name = R.name if (R.id == CAPSAICIN) display_name = "Hotsauce" if (R.id == FROSTOIL) display_name = "Coldsauce" dat += {"<B>[display_name]:</B> [R.volume] unit\s<BR>"} return dat /obj/get_heat_conductivity() //So keeping something in a closet can have an insulating effect. return 0.5 //This subtype is used by stuff that should generally not be disturbed by those procs /obj/abstract anchored = TRUE /obj/abstract/cultify() return /obj/abstract/ex_act() return /obj/abstract/emp_act() return /obj/abstract/blob_act() return /obj/abstract/singularity_act() return