Merge branch 'master' of https://github.com/Citadel-Station-13/Citadel-Station-13 into Ghommie-cit792
This commit is contained in:
@@ -22,8 +22,8 @@ GLOBAL_LIST_INIT(bitflags, list(1, 2, 4, 8, 16, 32, 64, 128, 256, 512, 1024, 204
|
||||
//FLAGS BITMASK
|
||||
///This flag is what recursive_hear_check() uses to determine wether to add an item to the hearer list or not.
|
||||
#define HEAR_1 (1<<3)
|
||||
///Projectiels will check ricochet on things impacted that have this.
|
||||
#define CHECK_RICOCHET_1 (1<<4)
|
||||
///Projectiles will use default chance-based ricochet handling on things with this.
|
||||
#define DEFAULT_RICOCHET_1 (1<<4)
|
||||
///Conducts electricity (metal etc.).
|
||||
#define CONDUCT_1 (1<<5)
|
||||
///For machines and structures that should not break into parts, eg, holodeck stuff.
|
||||
@@ -141,3 +141,23 @@ GLOBAL_LIST_INIT(bitflags, list(1, 2, 4, 8, 16, 32, 64, 128, 256, 512, 1024, 204
|
||||
// melee_attack_chain() attackchain_flags
|
||||
/// The attack is from a parry counterattack.
|
||||
#define ATTACKCHAIN_PARRY_COUNTERATTACK (1<<0)
|
||||
|
||||
/// If the thing can reflect light (lasers/energy)
|
||||
#define RICOCHET_SHINY (1<<0)
|
||||
/// If the thing can reflect matter (bullets/bomb shrapnel)
|
||||
#define RICOCHET_HARD (1<<1)
|
||||
|
||||
#define KEEP_TOGETHER_ORIGINAL "keep_together_original"
|
||||
|
||||
//setter for KEEP_TOGETHER to allow for multiple sources to set and unset it
|
||||
#define ADD_KEEP_TOGETHER(x, source)\
|
||||
if ((x.appearance_flags & KEEP_TOGETHER) && !HAS_TRAIT(x, TRAIT_KEEP_TOGETHER)) ADD_TRAIT(x, TRAIT_KEEP_TOGETHER, KEEP_TOGETHER_ORIGINAL); \
|
||||
ADD_TRAIT(x, TRAIT_KEEP_TOGETHER, source);\
|
||||
x.appearance_flags |= KEEP_TOGETHER
|
||||
|
||||
#define REMOVE_KEEP_TOGETHER(x, source)\
|
||||
REMOVE_TRAIT(x, TRAIT_KEEP_TOGETHER, source);\
|
||||
if(HAS_TRAIT_FROM_ONLY(x, TRAIT_KEEP_TOGETHER, KEEP_TOGETHER_ORIGINAL))\
|
||||
REMOVE_TRAIT(x, TRAIT_KEEP_TOGETHER, KEEP_TOGETHER_ORIGINAL);\
|
||||
else if(!HAS_TRAIT(x, TRAIT_KEEP_TOGETHER))\
|
||||
x.appearance_flags &= ~KEEP_TOGETHER
|
||||
|
||||
@@ -52,3 +52,4 @@
|
||||
#define ORGAN_VITAL (1<<4) //Currently only the brain
|
||||
#define ORGAN_NO_SPOIL (1<<5) //Do not spoil under any circumstances
|
||||
#define ORGAN_NO_DISMEMBERMENT (1<<6) //Immune to disembowelment.
|
||||
#define ORGAN_EDIBLE (1<<5) //is a snack? :D
|
||||
@@ -11,6 +11,17 @@
|
||||
#define NUKE_RESULT_WRONG_STATION 7
|
||||
#define NUKE_RESULT_WRONG_STATION_DEAD 8
|
||||
|
||||
//fugitive end results
|
||||
#define FUGITIVE_RESULT_BADASS_HUNTER 0
|
||||
#define FUGITIVE_RESULT_POSTMORTEM_HUNTER 1
|
||||
#define FUGITIVE_RESULT_MAJOR_HUNTER 2
|
||||
#define FUGITIVE_RESULT_HUNTER_VICTORY 3
|
||||
#define FUGITIVE_RESULT_MINOR_HUNTER 4
|
||||
#define FUGITIVE_RESULT_STALEMATE 5
|
||||
#define FUGITIVE_RESULT_MINOR_FUGITIVE 6
|
||||
#define FUGITIVE_RESULT_FUGITIVE_VICTORY 7
|
||||
#define FUGITIVE_RESULT_MAJOR_FUGITIVE 8
|
||||
|
||||
#define APPRENTICE_DESTRUCTION "destruction"
|
||||
#define APPRENTICE_BLUESPACE "bluespace"
|
||||
#define APPRENTICE_ROBELESS "robeless"
|
||||
|
||||
@@ -59,6 +59,7 @@
|
||||
#define ANTAG_HUD_CLOCKWORK 22
|
||||
#define ANTAG_HUD_BROTHER 23
|
||||
#define ANTAG_HUD_BLOODSUCKER 24
|
||||
#define ANTAG_HUD_FUGITIVE 25
|
||||
|
||||
// Notification action types
|
||||
#define NOTIFY_JUMP "jump"
|
||||
|
||||
@@ -32,4 +32,8 @@
|
||||
list("", "\improper S.T.E.A.L.T.H. pod MKVII", "A supply pod that, under normal circumstances, is completely invisible to conventional methods of detection. How are you even seeing this?"),\
|
||||
list("gondolapod", "gondola", "The silent walker. This one seems to be part of a delivery agency."),\
|
||||
list("", "", "")\
|
||||
)
|
||||
)
|
||||
|
||||
#define PACK_GOODY_NONE 0
|
||||
#define PACK_GOODY_PUBLIC 1 //can be bought by both privates and cargo
|
||||
#define PACK_GOODY_PRIVATE 2 //can be bought only by privates
|
||||
+19
-10
@@ -163,9 +163,8 @@ GLOBAL_LIST_INIT(shove_disarming_types, typecacheof(list(
|
||||
/obj/item/gun)))
|
||||
|
||||
|
||||
//Combat object defines
|
||||
|
||||
//Embedded objects
|
||||
|
||||
#define EMBEDDED_PAIN_CHANCE 15 //Chance for embedded objects to cause pain (damage user)
|
||||
#define EMBEDDED_ITEM_FALLOUT 5 //Chance for embedded object to fall out (causing pain but removing the object)
|
||||
#define EMBED_CHANCE 45 //Chance for an object to embed into somebody when thrown (if it's sharp)
|
||||
@@ -174,7 +173,16 @@ GLOBAL_LIST_INIT(shove_disarming_types, typecacheof(list(
|
||||
#define EMBEDDED_IMPACT_PAIN_MULTIPLIER 4 //Coefficient of multiplication for the damage the item does when it first embeds (this*item.w_class)
|
||||
#define EMBED_THROWSPEED_THRESHOLD 4 //The minimum value of an item's throw_speed for it to embed (Unless it has embedded_ignore_throwspeed_threshold set to 1)
|
||||
#define EMBEDDED_UNSAFE_REMOVAL_PAIN_MULTIPLIER 8 //Coefficient of multiplication for the damage the item does when removed without a surgery (this*item.w_class)
|
||||
#define EMBEDDED_UNSAFE_REMOVAL_TIME 150 //A Time in ticks, total removal time = (this/item.w_class)
|
||||
#define EMBEDDED_UNSAFE_REMOVAL_TIME 30 //A Time in ticks, total removal time = (this*item.w_class)
|
||||
#define EMBEDDED_JOSTLE_CHANCE 5 //Chance for embedded objects to cause pain every time they move (jostle)
|
||||
#define EMBEDDED_JOSTLE_PAIN_MULTIPLIER 1 //Coefficient of multiplication for the damage the item does while
|
||||
#define EMBEDDED_PAIN_STAM_PCT 0.0 //This percentage of all pain will be dealt as stam damage rather than brute (0-1)
|
||||
#define EMBED_CHANCE_TURF_MOD -15 //You are this many percentage points less likely to embed into a turf (good for things glass shards and spears vs walls)
|
||||
|
||||
#define EMBED_HARMLESS list("pain_mult" = 0, "jostle_pain_mult" = 0, "ignore_throwspeed_threshold" = TRUE)
|
||||
#define EMBED_HARMLESS_SUPERIOR list("pain_mult" = 0, "jostle_pain_mult" = 0, "ignore_throwspeed_threshold" = TRUE, "embed_chance" = 100, "fall_chance" = 0.1)
|
||||
#define EMBED_POINTY list("ignore_throwspeed_threshold" = TRUE)
|
||||
#define EMBED_POINTY_SUPERIOR list("embed_chance" = 100, "ignore_throwspeed_threshold" = TRUE)
|
||||
|
||||
//Gun weapon weight
|
||||
#define WEAPON_LIGHT 1
|
||||
@@ -189,6 +197,14 @@ GLOBAL_LIST_INIT(shove_disarming_types, typecacheof(list(
|
||||
#define EGUN_SELFCHARGE 1
|
||||
#define EGUN_SELFCHARGE_BORG 2
|
||||
|
||||
//Gun suppression
|
||||
#define SUPPRESSED_NONE 0
|
||||
#define SUPPRESSED_QUIET 1 ///standard suppressed
|
||||
#define SUPPRESSED_VERY 2 /// no message
|
||||
|
||||
//Nice shot bonus
|
||||
#define NICE_SHOT_RICOCHET_BONUS 10 //if the shooter has the NICE_SHOT trait and they fire a ricocheting projectile, add this to the ricochet chance and auto aim angle
|
||||
|
||||
///Time to spend without clicking on other things required for your shots to become accurate.
|
||||
#define GUN_AIMING_TIME (2 SECONDS)
|
||||
|
||||
@@ -273,10 +289,3 @@ GLOBAL_LIST_INIT(shove_disarming_types, typecacheof(list(
|
||||
* a "inefficiently" prefix will be added to the message.
|
||||
*/
|
||||
#define FEEBLE_ATTACK_MSG_THRESHOLD 0.5
|
||||
|
||||
|
||||
//bullet_act() return values
|
||||
#define BULLET_ACT_HIT "HIT" //It's a successful hit, whatever that means in the context of the thing it's hitting.
|
||||
#define BULLET_ACT_BLOCK "BLOCK" //It's a blocked hit, whatever that means in the context of the thing it's hitting.
|
||||
#define BULLET_ACT_FORCE_PIERCE "PIERCE" //It pierces through the object regardless of the bullet being piercing by default.
|
||||
#define BULLET_ACT_TURF "TURF" //It hit us but it should hit something on the same turf too. Usually used for turfs.
|
||||
|
||||
@@ -26,10 +26,16 @@
|
||||
#define COMPONENT_ADD_TRAIT (1<<0)
|
||||
#define COMPONENT_REMOVE_TRAIT (1<<1)
|
||||
|
||||
/// fires on the target datum when an element is attached to it (/datum/element)
|
||||
#define COMSIG_ELEMENT_ATTACH "element_attach"
|
||||
/// fires on the target datum when an element is attached to it (/datum/element)
|
||||
#define COMSIG_ELEMENT_DETACH "element_detach"
|
||||
|
||||
// /atom signals
|
||||
#define COMSIG_PARENT_ATTACKBY "atom_attackby" //from base of atom/attackby(): (/obj/item, /mob/living, params)
|
||||
#define COMPONENT_NO_AFTERATTACK 1 //Return this in response if you don't want afterattack to be called
|
||||
#define COMSIG_ATOM_HULK_ATTACK "hulk_attack" //from base of atom/attack_hulk(): (/mob/living/carbon/human)
|
||||
#define COMSIG_ATOM_ATTACK_ANIMAL "attack_animal" //from base of atom/animal_attack(): (/mob/user)
|
||||
#define COMSIG_PARENT_EXAMINE "atom_examine" //from base of atom/examine(): (/mob, list/examine_return_text)
|
||||
#define COMSIG_ATOM_GET_EXAMINE_NAME "atom_examine_name" //from base of atom/get_examine_name(): (/mob, list/overrides)
|
||||
//Positions for overrides list
|
||||
@@ -227,10 +233,16 @@
|
||||
#define COMSIG_LIVING_STATUS_STAGGER "living_stagger" //from base of mob/living/Stagger() (amount, update, ignore)
|
||||
#define COMPONENT_NO_STUN 1 //For all of them
|
||||
|
||||
#define COMSIG_LIVING_LIFE "life_tick" //from base of mob/living/Life() (seconds, times_fired)
|
||||
#define COMPONENT_INTERRUPT_LIFE_BIOLOGICAL 1 // interrupt biological processes
|
||||
#define COMPONENT_INTERRUPT_LIFE_PHYSICAL 2 // interrupt physical handling
|
||||
|
||||
// /mob/living/carbon signals
|
||||
#define COMSIG_CARBON_SOUNDBANG "carbon_soundbang" //from base of mob/living/carbon/soundbang_act(): (list(intensity))
|
||||
#define COMSIG_CARBON_IDENTITY_TRANSFERRED_TO "carbon_id_transferred_to" //from datum/dna/transfer_identity(): (datum/dna, transfer_SE)
|
||||
#define COMSIG_CARBON_TACKLED "carbon_tackled" //sends from tackle.dm on tackle completion
|
||||
#define COMSIG_CARBON_EMBED_RIP "item_embed_start_rip" // defined twice, in carbon and human's topics, fired when interacting with a valid embedded_object to pull it out (mob/living/carbon/target, /obj/item, /obj/item/bodypart/L)
|
||||
#define COMSIG_CARBON_EMBED_REMOVAL "item_embed_remove_safe" // called when removing a given item from a mob, from mob/living/carbon/remove_embedded_object(mob/living/carbon/target, /obj/item)
|
||||
|
||||
// /mob/living/silicon signals
|
||||
#define COMSIG_ROBOT_UPDATE_ICONS "robot_update_icons" //from base of robot/update_icons(): ()
|
||||
@@ -243,6 +255,9 @@
|
||||
#define COMSIG_OBJ_DECONSTRUCT "obj_deconstruct" //from base of obj/deconstruct(): (disassembled)
|
||||
#define COMSIG_OBJ_BREAK "obj_break" //from base of /obj/obj_break(): (damage_flag)
|
||||
#define COMSIG_OBJ_SETANCHORED "obj_setanchored" //called in /obj/structure/setAnchored(): (value)
|
||||
#define COMSIG_OBJ_ATTACK_GENERIC "obj_attack_generic" //from base of atom/animal_attack(): (/mob/user)
|
||||
#define COMPONENT_STOP_GENERIC_ATTACK 1
|
||||
|
||||
|
||||
// /machinery signals
|
||||
#define COMSIG_MACHINE_EJECT_OCCUPANT "eject_occupant" //from base of obj/machinery/dropContents() (occupant)
|
||||
@@ -269,6 +284,7 @@
|
||||
#define COMSIG_ITEM_IMBUE_SOUL "item_imbue_soul" //return a truthy value to prevent ensouling, checked in /obj/effect/proc_holder/spell/targeted/lichdom/cast(): (mob/user)
|
||||
#define COMSIG_ITEM_HIT_REACT "item_hit_react" //from base of obj/item/hit_reaction(): (list/args)
|
||||
#define COMSIG_ITEM_WEARERCROSSED "wearer_crossed" //called on item when crossed by something (): (/atom/movable)
|
||||
#define COMSIG_ITEM_MICROWAVE_ACT "microwave_act" //called on item when microwaved (): (obj/machinery/microwave/M)
|
||||
#define COMSIG_ITEM_WORN_OVERLAYS "item_worn_overlays" //from base of obj/item/worn_overlays(): (isinhands, icon_file, used_state, style_flags, list/overlays)
|
||||
// THE FOLLOWING TWO BLOCKS SHOULD RETURN BLOCK FLAGS AS DEFINED IN __DEFINES/combat.dm!
|
||||
#define COMSIG_ITEM_CHECK_BLOCK "check_block" //from base of obj/item/check_block(): (mob/living/owner, atom/object, damage, attack_text, attack_type, armour_penetration, mob/attacker, def_zone, final_block_chance, list/block_return)
|
||||
@@ -277,9 +293,15 @@
|
||||
#define COMSIG_ITEM_MOUSE_EXIT "item_mouse_exit" //from base of obj/item/MouseExited(): (location, control, params)
|
||||
#define COMSIG_ITEM_MOUSE_ENTER "item_mouse_enter" //from base of obj/item/MouseEntered(): (location, control, params)
|
||||
#define COMSIG_ITEM_DECONSTRUCTOR_DEEPSCAN "deconstructor_deepscan" //Called by deconstructive analyzers deepscanning an item: (obj/machinery/rnd/destructive_analyzer/analyzer_machine, mob/user, list/information_list)
|
||||
#define COMSIG_ITEM_DISABLE_EMBED "item_disable_embed" ///from [/obj/item/proc/disableEmbedding]:
|
||||
#define COMSIG_MINE_TRIGGERED "minegoboom" ///from [/obj/effect/mine/proc/triggermine]:
|
||||
// Uncovered information
|
||||
#define COMPONENT_DEEPSCAN_UNCOVERED_INFORMATION 1
|
||||
|
||||
// /obj/item/grenade signals
|
||||
#define COMSIG_GRENADE_PRIME "grenade_prime" //called in /obj/item/gun/process_fire (user, target, params, zone_override)
|
||||
#define COMSIG_GRENADE_ARMED "grenade_armed" //called in /obj/item/gun/process_fire (user, target, params, zone_override)
|
||||
|
||||
// /obj/item/clothing signals
|
||||
#define COMSIG_SHOES_STEP_ACTION "shoes_step_action" //from base of obj/item/clothing/shoes/proc/step_action(): ()
|
||||
#define COMSIG_SUIT_MADE_HELMET "suit_made_helmet" //from base of obj/item/clothing/suit/MakeHelmet(): (helmet)
|
||||
@@ -307,8 +329,15 @@
|
||||
#define COMSIG_PEN_ROTATED "pen_rotated" //called after rotation in /obj/item/pen/attack_self(): (rotation, mob/living/carbon/user)
|
||||
|
||||
// /obj/item/projectile signals (sent to the firer)
|
||||
#define COMSIG_PROJECTILE_SELF_ON_HIT "projectile_self_on_hit" // from base of /obj/item/projectile/proc/on_hit(): (atom/movable/firer, atom/target, Angle)
|
||||
#define COMSIG_PROJECTILE_ON_HIT "projectile_on_hit" // from base of /obj/item/projectile/proc/on_hit(): (atom/movable/firer, atom/target, Angle)
|
||||
#define COMSIG_PROJECTILE_BEFORE_FIRE "projectile_before_fire" // from base of /obj/item/projectile/proc/fire(): (obj/item/projectile, atom/original_target)
|
||||
#define COMSIG_PROJECTILE_FIRE "projectile_fire" ///from the base of /obj/projectile/proc/fire(): ()
|
||||
#define COMSIG_PROJECTILE_RANGE_OUT "projectile_range_out" // sent to targets during the process_hit proc of projectiles
|
||||
#define COMSIG_EMBED_TRY_FORCE "item_try_embed" // sent when trying to force an embed (mainly for projectiles, only used in the embed element)
|
||||
#define COMSIG_PROJECTILE_PREHIT "com_proj_prehit" ///sent to targets during the process_hit proc of projectiles
|
||||
|
||||
#define COMSIG_PELLET_CLOUD_INIT "pellet_cloud_init" // sent to targets during the process_hit proc of projectiles
|
||||
|
||||
// /mob/living/carbon/human signals
|
||||
#define COMSIG_HUMAN_MELEE_UNARMED_ATTACK "human_melee_unarmed_attack" //from mob/living/carbon/human/UnarmedAttack(): (atom/target)
|
||||
|
||||
@@ -18,4 +18,8 @@
|
||||
#define DRINK_VERYGOOD 3
|
||||
#define DRINK_FANTASTIC 4
|
||||
#define FOOD_AMAZING 5
|
||||
#define RACE_DRINK 6
|
||||
#define RACE_DRINK 6
|
||||
|
||||
#define FOOD_IN_CONTAINER (1<<0)
|
||||
|
||||
#define STOP_SERVING_BREAKFAST (15 MINUTES)
|
||||
|
||||
@@ -6,6 +6,7 @@
|
||||
#define FOOTSTEP_GRASS "grass"
|
||||
#define FOOTSTEP_WATER "water"
|
||||
#define FOOTSTEP_LAVA "lava"
|
||||
#define FOOTSTEP_MEAT "meat"
|
||||
//barefoot sounds
|
||||
#define FOOTSTEP_WOOD_BAREFOOT "woodbarefoot"
|
||||
#define FOOTSTEP_WOOD_CLAW "woodclaw"
|
||||
@@ -89,6 +90,8 @@ GLOBAL_LIST_INIT(footstep, list(
|
||||
'sound/effects/footstep/lava1.ogg',
|
||||
'sound/effects/footstep/lava2.ogg',
|
||||
'sound/effects/footstep/lava3.ogg'), 100, 0),
|
||||
FOOTSTEP_MEAT = list(list(
|
||||
'sound/effects/meatslap.ogg'), 100, 0)
|
||||
))
|
||||
|
||||
//bare footsteps lists
|
||||
@@ -131,6 +134,8 @@ GLOBAL_LIST_INIT(barefootstep, list(
|
||||
'sound/effects/footstep/lava1.ogg',
|
||||
'sound/effects/footstep/lava2.ogg',
|
||||
'sound/effects/footstep/lava3.ogg'), 100, 0),
|
||||
FOOTSTEP_MEAT = list(list(
|
||||
'sound/effects/meatslap.ogg'), 100, 0)
|
||||
))
|
||||
|
||||
//claw footsteps lists
|
||||
@@ -173,6 +178,8 @@ GLOBAL_LIST_INIT(clawfootstep, list(
|
||||
'sound/effects/footstep/lava1.ogg',
|
||||
'sound/effects/footstep/lava2.ogg',
|
||||
'sound/effects/footstep/lava3.ogg'), 100, 0),
|
||||
FOOTSTEP_MEAT = list(list(
|
||||
'sound/effects/meatslap.ogg'), 100, 0)
|
||||
))
|
||||
|
||||
//heavy footsteps list
|
||||
@@ -189,4 +196,6 @@ GLOBAL_LIST_INIT(heavyfootstep, list(
|
||||
'sound/effects/footstep/lava1.ogg',
|
||||
'sound/effects/footstep/lava2.ogg',
|
||||
'sound/effects/footstep/lava3.ogg'), 100, 0),
|
||||
FOOTSTEP_MEAT = list(list(
|
||||
'sound/effects/meatslap.ogg'), 100, 0)
|
||||
))
|
||||
|
||||
@@ -135,6 +135,8 @@ GLOBAL_LIST_INIT(turfs_without_ground, typecacheof(list(
|
||||
|
||||
#define iscat(A) (istype(A, /mob/living/simple_animal/pet/cat))
|
||||
|
||||
#define isdog(A) (istype(A, /mob/living/simple_animal/pet/dog))
|
||||
|
||||
#define iscorgi(A) (istype(A, /mob/living/simple_animal/pet/dog/corgi))
|
||||
|
||||
#define ishostile(A) (istype(A, /mob/living/simple_animal/hostile))
|
||||
@@ -180,6 +182,12 @@ GLOBAL_LIST_INIT(turfs_without_ground, typecacheof(list(
|
||||
|
||||
#define isitem(A) (istype(A, /obj/item))
|
||||
|
||||
#define isgrenade(A) (istype(A, /obj/item/grenade))
|
||||
|
||||
#define islandmine(A) (istype(A, /obj/effect/mine))
|
||||
|
||||
#define isammocasing(A) (istype(A, /obj/item/ammo_casing))
|
||||
|
||||
#define isidcard(I) (istype(I, /obj/item/card/id))
|
||||
|
||||
#define isstructure(A) (istype(A, /obj/structure))
|
||||
|
||||
@@ -4,8 +4,13 @@
|
||||
/// Hard materials, such as iron or metal
|
||||
#define MAT_CATEGORY_RIGID "rigid material"
|
||||
|
||||
///Use this flag on TRUE if you want the basic recipes
|
||||
#define MAT_CATEGORY_BASE_RECIPES "basic recipes"
|
||||
|
||||
/// Flag for atoms, this flag ensures it isn't re-colored by materials. Useful for snowflake icons such as default toolboxes.
|
||||
#define MATERIAL_COLOR (1<<0)
|
||||
#define MATERIAL_ADD_PREFIX (1<<1)
|
||||
#define MATERIAL_EFFECTS (1<<2)
|
||||
#define MATERIAL_AFFECT_STATISTICS (1<<3)
|
||||
#define MATERIAL_AFFECT_STATISTICS (1<<3)
|
||||
|
||||
#define MATERIAL_SOURCE(mat) "[mat.name]_material"
|
||||
@@ -3,7 +3,7 @@
|
||||
/// How much someone is slowed from fireman carrying a human
|
||||
#define FIREMAN_CARRY_SLOWDOWN 0
|
||||
/// How much someone is slowed by piggybacking a human
|
||||
#define PIGGYBACK_CARRY_SLOWDOWN 1
|
||||
#define PIGGYBACK_CARRY_SLOWDOWN 0
|
||||
/// slowdown when in softcrit. Note that crawling slowdown will also apply at the same time!
|
||||
#define SOFTCRIT_ADD_SLOWDOWN 2
|
||||
/// slowdown when crawling
|
||||
|
||||
@@ -0,0 +1,14 @@
|
||||
/// This atom should be ricocheted off of from its inherent properties using standard % chance handling.
|
||||
#define PROJECTILE_RICOCHET_YES 1
|
||||
/// This atom should not be ricocheted off of from its inherent properties.
|
||||
#define PROJECTILE_RICOCHET_NO 2
|
||||
/// This atom should prevent any kind of projectile ricochet from its inherent properties.
|
||||
#define PROJECTILE_RICOCHET_PREVENT 3
|
||||
/// This atom should force a projectile ricochet from its inherent properties.
|
||||
#define PROJECTILE_RICOCHET_FORCE 4
|
||||
|
||||
//bullet_act() return values
|
||||
#define BULLET_ACT_HIT "HIT" //It's a successful hit, whatever that means in the context of the thing it's hitting.
|
||||
#define BULLET_ACT_BLOCK "BLOCK" //It's a blocked hit, whatever that means in the context of the thing it's hitting.
|
||||
#define BULLET_ACT_FORCE_PIERCE "PIERCE" //It pierces through the object regardless of the bullet being piercing by default.
|
||||
#define BULLET_ACT_TURF "TURF" //It hit us but it should hit something on the same turf too. Usually used for turfs.
|
||||
@@ -27,6 +27,7 @@
|
||||
#define BOT_NAV 15 // computing navigation
|
||||
#define BOT_WAIT_FOR_NAV 16 // waiting for nav computation
|
||||
#define BOT_NO_ROUTE 17 // no destination beacon found (or no route)
|
||||
#define BOT_TIPPED 18 // someone tipped a medibot over ;_;
|
||||
|
||||
//Bot types
|
||||
#define SEC_BOT (1<<0) // Secutritrons (Beepsky) and ED-209s
|
||||
|
||||
@@ -7,6 +7,8 @@
|
||||
#define SHUTTLE_STRANDED "stranded"
|
||||
#define SHUTTLE_ESCAPE "escape"
|
||||
#define SHUTTLE_ENDGAME "endgame: game over"
|
||||
#define SHUTTLE_RECHARGING "recharging"
|
||||
#define SHUTTLE_PREARRIVAL "landing"
|
||||
|
||||
#define EMERGENCY_IDLE_OR_RECALLED (SSshuttle.emergency && ((SSshuttle.emergency.mode == SHUTTLE_IDLE) || (SSshuttle.emergency.mode == SHUTTLE_RECALL)))
|
||||
#define EMERGENCY_ESCAPED_OR_ENDGAMED (SSshuttle.emergency && ((SSshuttle.emergency.mode == SHUTTLE_ESCAPE) || (SSshuttle.emergency.mode == SHUTTLE_ENDGAME)))
|
||||
|
||||
@@ -6,10 +6,26 @@
|
||||
#define RETURN_TYPE(X) set SpacemanDMM_return_type = X
|
||||
#define SHOULD_CALL_PARENT(X) set SpacemanDMM_should_call_parent = X
|
||||
#define UNLINT(X) SpacemanDMM_unlint(X)
|
||||
#define SHOULD_NOT_OVERRIDE(X) set SpacemanDMM_should_not_override = X
|
||||
#define SHOULD_NOT_SLEEP(X) set SpacemanDMM_should_not_sleep = X
|
||||
#define SHOULD_BE_PURE(X) set SpacemanDMM_should_be_pure = X
|
||||
#define PRIVATE_PROC(X) set SpacemanDMM_private_proc = X
|
||||
#define PROTECTED_PROC(X) set SpacemanDMM_protected_proc = X
|
||||
#define VAR_FINAL var/SpacemanDMM_final
|
||||
#define VAR_PRIVATE var/SpacemanDMM_private
|
||||
#define VAR_PROTECTED var/SpacemanDMM_protected
|
||||
#else
|
||||
#define RETURN_TYPE(X)
|
||||
#define SHOULD_CALL_PARENT(X)
|
||||
#define UNLINT(X) X
|
||||
#define SHOULD_NOT_OVERRIDE(X)
|
||||
#define SHOULD_NOT_SLEEP(X)
|
||||
#define SHOULD_BE_PURE(X)
|
||||
#define PRIVATE_PROC(X)
|
||||
#define PROTECTED_PROC(X)
|
||||
#define VAR_FINAL var
|
||||
#define VAR_PRIVATE var
|
||||
#define VAR_PROTECTED var
|
||||
#endif
|
||||
|
||||
/world/proc/enable_debugger()
|
||||
|
||||
@@ -96,6 +96,8 @@
|
||||
|
||||
#define STATUS_EFFECT_SPASMS /datum/status_effect/spasms //causes random muscle spasms
|
||||
|
||||
#define STATUS_EFFECT_FAKE_VIRUS /datum/status_effect/fake_virus //gives you fluff messages for cough, sneeze, headache, etc but without an actual virus
|
||||
|
||||
#define STATUS_EFFECT_BREASTS_ENLARGEMENT /datum/status_effect/chem/breast_enlarger //Applied slowdown due to the ominous bulk.
|
||||
|
||||
#define STATUS_EFFECT_PENIS_ENLARGEMENT /datum/status_effect/chem/penis_enlarger //More applied slowdown, just like the above.
|
||||
|
||||
@@ -61,12 +61,20 @@
|
||||
} while (0)
|
||||
#define HAS_TRAIT(target, trait) (target.status_traits ? (target.status_traits[trait] ? TRUE : FALSE) : FALSE)
|
||||
#define HAS_TRAIT_FROM(target, trait, source) (target.status_traits ? (target.status_traits[trait] ? (source in target.status_traits[trait]) : FALSE) : FALSE)
|
||||
#define HAS_TRAIT_FROM_ONLY(target, trait, source) (\
|
||||
target.status_traits ?\
|
||||
(target.status_traits[trait] ?\
|
||||
((source in target.status_traits[trait]) && (length(target.status_traits) == 1))\
|
||||
: FALSE)\
|
||||
: FALSE)
|
||||
#define HAS_TRAIT_NOT_FROM(target, trait, source) (target.status_traits ? (target.status_traits[trait] ? (length(target.status_traits[trait] - source) > 0) : FALSE) : FALSE)
|
||||
|
||||
//mob traits
|
||||
#define TRAIT_BLIND "blind"
|
||||
#define TRAIT_MUTE "mute"
|
||||
#define TRAIT_EMOTEMUTE "emotemute"
|
||||
#define TRAIT_LOOC_MUTE "looc_mute" //Just like unconsciousness, it disables LOOC salt.
|
||||
#define TRAIT_AOOC_MUTE "aooc_mute" //Same as above but for AOOC.
|
||||
#define TRAIT_DEAF "deaf"
|
||||
#define TRAIT_NEARSIGHT "nearsighted"
|
||||
#define TRAIT_FAT "fat"
|
||||
@@ -194,6 +202,7 @@
|
||||
#define TRAIT_NO_ALCOHOL "alcohol_intolerance"
|
||||
#define TRAIT_MUTATION_STASIS "mutation_stasis" //Prevents processed genetics mutations from processing.
|
||||
#define TRAIT_FAST_PUMP "fast_pump"
|
||||
#define TRAIT_NICE_SHOT "nice_shot" //hnnnnnnnggggg..... you're pretty good....
|
||||
|
||||
// mobility flag traits
|
||||
// IN THE FUTURE, IT WOULD BE NICE TO DO SOMETHING SIMILAR TO https://github.com/tgstation/tgstation/pull/48923/files (ofcourse not nearly the same because I have my.. thoughts on it)
|
||||
@@ -223,6 +232,8 @@
|
||||
#define VEHICLE_TRAIT "vehicle" // inherited from riding vehicles
|
||||
#define INNATE_TRAIT "innate"
|
||||
|
||||
///Used for managing KEEP_TOGETHER in [appearance_flags]
|
||||
#define TRAIT_KEEP_TOGETHER "keep-together"
|
||||
|
||||
// item traits
|
||||
#define TRAIT_NODROP "nodrop"
|
||||
@@ -254,7 +265,7 @@
|
||||
#define BOOK_TRAIT "granter (book)" // knowledge is power
|
||||
|
||||
// unique trait sources, still defines
|
||||
#define STATUE_MUTE "statue"
|
||||
#define STATUE_TRAIT "statue"
|
||||
#define CLONING_POD_TRAIT "cloning-pod"
|
||||
#define VIRTUAL_REALITY_TRAIT "vr_trait"
|
||||
#define CHANGELING_DRAIN "drain"
|
||||
@@ -299,3 +310,4 @@
|
||||
#define ACTIVE_BLOCK_TRAIT "active_block"
|
||||
/// This trait is added by the parry system.
|
||||
#define ACTIVE_PARRY_TRAIT "active_parry"
|
||||
#define STICKY_NODROP "sticky-nodrop" //sticky nodrop sounds like a bad soundcloud rapper's name
|
||||
@@ -55,7 +55,7 @@
|
||||
WRITE_LOG(GLOB.world_game_log, "ADMIN: DSAY: [text]")
|
||||
|
||||
/proc/log_consent(text)
|
||||
WRITE_LOG(GLOB.world_game_log,"CONSENT: [text]")
|
||||
WRITE_LOG(GLOB.world_game_log, "CONSENT: [text]")
|
||||
|
||||
/* All other items are public. */
|
||||
/proc/log_game(text)
|
||||
@@ -66,6 +66,9 @@
|
||||
if (CONFIG_GET(flag/log_virus))
|
||||
WRITE_LOG(GLOB.world_virus_log, "VIRUS: [text]")
|
||||
|
||||
/proc/log_asset(text)
|
||||
WRITE_LOG(GLOB.world_asset_log, "ASSET: [text]")
|
||||
|
||||
/proc/log_access(text)
|
||||
if (CONFIG_GET(flag/log_access))
|
||||
WRITE_LOG(GLOB.world_game_log, "ACCESS: [text]")
|
||||
|
||||
@@ -3,7 +3,7 @@
|
||||
for(var/file in args)
|
||||
src << browse_rsc(file)
|
||||
|
||||
/client/proc/browse_files(root="data/logs/", max_iterations=10, list/valid_extensions=list("txt","log","htm", "html", "md"))
|
||||
/client/proc/browse_files(root="data/logs/", max_iterations=10, list/valid_extensions=list("txt","log","htm", "html", "md", "json"))
|
||||
var/path = root
|
||||
|
||||
for(var/i=0, i<max_iterations, i++)
|
||||
|
||||
@@ -375,6 +375,8 @@ GLOBAL_LIST_EMPTY(species_list)
|
||||
override = TRUE
|
||||
if(HAS_TRAIT(M, TRAIT_SIXTHSENSE))
|
||||
override = TRUE
|
||||
if(SSticker.current_state == GAME_STATE_FINISHED)
|
||||
override = TRUE
|
||||
if(isnewplayer(M) && !override)
|
||||
continue
|
||||
if(M.stat != DEAD && !override)
|
||||
|
||||
@@ -233,6 +233,7 @@
|
||||
for(var/antag_name in total_antagonists)
|
||||
var/list/L = total_antagonists[antag_name]
|
||||
log_game("[antag_name]s :[L.Join(", ")].")
|
||||
set_observer_default_invisibility(0, "<span class='warning'>The round is over! You are now visible to the living.</span>")
|
||||
|
||||
CHECK_TICK
|
||||
SSdbcore.SetRoundEnd()
|
||||
|
||||
@@ -675,12 +675,6 @@ Turf and target are separate in case you want to teleport some distance from a t
|
||||
loc = loc.loc
|
||||
return null
|
||||
|
||||
//For objects that should embed, but make no sense being is_sharp or is_pointed()
|
||||
//e.g: rods
|
||||
GLOBAL_LIST_INIT(can_embed_types, typecacheof(list(
|
||||
/obj/item/stack/rods,
|
||||
/obj/item/pipe)))
|
||||
|
||||
/*
|
||||
Checks if that loc and dir has an item on the wall
|
||||
*/
|
||||
|
||||
@@ -125,7 +125,7 @@ GLOBAL_LIST_INIT(bitfields, list(
|
||||
"UNUSED_RESERVATION_TURF_1" = UNUSED_RESERVATION_TURF_1,
|
||||
"CAN_BE_DIRTY_1" = CAN_BE_DIRTY_1,
|
||||
"HEAR_1" = HEAR_1,
|
||||
"CHECK_RICOCHET_1" = CHECK_RICOCHET_1,
|
||||
"DEFAULT_RICOCHET_1" = DEFAULT_RICOCHET_1,
|
||||
"CONDUCT_1" = CONDUCT_1,
|
||||
"NO_LAVA_GEN_1" = NO_LAVA_GEN_1,
|
||||
"NODECONSTRUCT_1" = NODECONSTRUCT_1,
|
||||
@@ -140,6 +140,10 @@ GLOBAL_LIST_INIT(bitfields, list(
|
||||
"BLOCK_FACE_ATOM_1" = BLOCK_FACE_ATOM_1,
|
||||
"PREVENT_CONTENTS_EXPLOSION_1" = PREVENT_CONTENTS_EXPLOSION_1
|
||||
),
|
||||
"flags_ricochet" = list(
|
||||
"RICOCHET_SHINY" = RICOCHET_SHINY,
|
||||
"RICOCHET_HARD" = RICOCHET_HARD
|
||||
),
|
||||
"clothing_flags" = list(
|
||||
"LAVAPROTECT" = LAVAPROTECT,
|
||||
"STOPSPRESSUREDAMAGE" = STOPSPRESSUREDAMAGE,
|
||||
|
||||
@@ -223,3 +223,6 @@ GLOBAL_LIST_INIT(station_numerals, greek_letters + phonetic_alphabet + numbers_a
|
||||
GLOBAL_LIST_INIT(admiral_messages, list("Do you know how expensive these stations are?","Stop wasting my time.","I was sleeping, thanks a lot.","Stand and fight you cowards!","You knew the risks coming in.","Stop being paranoid.","Whatever's broken just build a new one.","No.", "<i>null</i>","<i>Error: No comment given.</i>", "It's a good day to die!"))
|
||||
|
||||
GLOBAL_LIST_INIT(redacted_strings, list("\[REDACTED\]", "\[CLASSIFIED\]", "\[ARCHIVED\]", "\[EXPLETIVE DELETED\]", "\[EXPUNGED\]", "\[INFORMATION ABOVE YOUR SECURITY CLEARANCE\]", "\[MOVE ALONG CITIZEN\]", "\[NOTHING TO SEE HERE\]", "\[ACCESS DENIED\]"))
|
||||
|
||||
|
||||
GLOBAL_LIST_INIT(wisdoms, world.file2list("strings/wisdoms.txt"))
|
||||
|
||||
@@ -51,7 +51,7 @@ GLOBAL_LIST_INIT(maintenance_loot, list(
|
||||
/obj/item/airlock_painter = 1,
|
||||
/obj/item/stack/cable_coil/random = 4,
|
||||
/obj/item/stack/cable_coil/random/five = 6,
|
||||
/obj/item/stack/medical/bruise_pack = 1,
|
||||
/obj/item/stack/medical/suture = 1,
|
||||
/obj/item/stack/rods/ten = 9,
|
||||
/obj/item/stack/rods/twentyfive = 1,
|
||||
/obj/item/stack/rods/fifty = 1,
|
||||
@@ -116,6 +116,7 @@ GLOBAL_LIST_INIT(maintenance_loot, list(
|
||||
/obj/item/autosurgeon/testicles = 1,
|
||||
/obj/item/storage/box/marshmallow = 2,
|
||||
/obj/item/clothing/gloves/tackler/offbrand = 1,
|
||||
/obj/item/stack/sticky_tape = 1,
|
||||
"" = 3
|
||||
))
|
||||
|
||||
|
||||
@@ -19,6 +19,7 @@
|
||||
#define POLL_IGNORE_WIZARD "wizard"
|
||||
#define POLL_IGNORE_CLONE "clone"
|
||||
#define POLL_IGNORE_CONTRACTOR_SUPPORT "contractor_support"
|
||||
#define POLL_IGNORE_FUGITIVE "fugitive"
|
||||
|
||||
GLOBAL_LIST_INIT(poll_ignore_desc, list(
|
||||
POLL_IGNORE_SENTIENCE_POTION = "Sentience potion",
|
||||
@@ -39,7 +40,8 @@ GLOBAL_LIST_INIT(poll_ignore_desc, list(
|
||||
POLL_IGNORE_DEMON = "Demons",
|
||||
POLL_IGNORE_WIZARD = "Wizards",
|
||||
POLL_IGNORE_CLONE = "Defective/SDGF clones",
|
||||
POLL_IGNORE_CONTRACTOR_SUPPORT = "Contractor Support Unit"
|
||||
POLL_IGNORE_CONTRACTOR_SUPPORT = "Contractor Support Unit",
|
||||
POLL_IGNORE_FUGITIVE = "Fugitive Hunter"
|
||||
))
|
||||
GLOBAL_LIST_INIT(poll_ignore, init_poll_ignore())
|
||||
|
||||
|
||||
@@ -28,6 +28,8 @@ GLOBAL_VAR(world_job_debug_log)
|
||||
GLOBAL_PROTECT(world_job_debug_log)
|
||||
GLOBAL_VAR(world_virus_log)
|
||||
GLOBAL_PROTECT(world_virus_log)
|
||||
GLOBAL_VAR(world_asset_log)
|
||||
GLOBAL_PROTECT(world_asset_log)
|
||||
GLOBAL_VAR(world_map_error_log)
|
||||
GLOBAL_PROTECT(world_map_error_log)
|
||||
GLOBAL_VAR(subsystem_log)
|
||||
|
||||
@@ -93,6 +93,7 @@ GLOBAL_LIST_INIT(traits_by_type, list(
|
||||
"TRAIT_PASSTABLE" = TRAIT_PASSTABLE,
|
||||
"TRAIT_GIANT" = TRAIT_GIANT,
|
||||
"TRAIT_DWARF" = TRAIT_DWARF,
|
||||
"TRAIT_NICE_SHOT" = TRAIT_NICE_SHOT,
|
||||
"TRAIT_COMBAT_MODE_LOCKED" = TRAIT_COMBAT_MODE_LOCKED,
|
||||
"TRAIT_SPRINT_LOCKED" = TRAIT_SPRINT_LOCKED,
|
||||
"TRAIT_AUTO_CATCH_ITEM" = TRAIT_AUTO_CATCH_ITEM,
|
||||
@@ -116,7 +117,8 @@ GLOBAL_LIST_INIT(traits_by_type, list(
|
||||
"TRAIT_MASO" = TRAIT_MASO,
|
||||
"TRAIT_HIGH_BLOOD" = TRAIT_HIGH_BLOOD,
|
||||
"TRAIT_EMPATH" = TRAIT_EMPATH,
|
||||
"TRAIT_FRIENDLY" = TRAIT_FRIENDLY
|
||||
"TRAIT_FRIENDLY" = TRAIT_FRIENDLY,
|
||||
"TRAIT_NICE_SHOT" = TRAIT_NICE_SHOT
|
||||
),
|
||||
/obj/item/bodypart = list(
|
||||
"TRAIT_PARALYSIS" = TRAIT_PARALYSIS
|
||||
|
||||
@@ -76,7 +76,7 @@
|
||||
if(check_click_intercept(params,A))
|
||||
return
|
||||
|
||||
if(notransform)
|
||||
if(mob_transforming)
|
||||
return
|
||||
|
||||
if(SEND_SIGNAL(src, COMSIG_MOB_CLICKON, A, params) & COMSIG_MOB_CANCEL_CLICKON)
|
||||
|
||||
@@ -242,7 +242,7 @@ If you're feeling frisky, examine yourself and click the underlined item to pull
|
||||
|
||||
/obj/screen/alert/embeddedobject/Click()
|
||||
if(isliving(usr))
|
||||
var/mob/living/carbon/human/M = usr
|
||||
var/mob/living/carbon/M = usr
|
||||
return M.help_shake_act(M)
|
||||
|
||||
/obj/screen/alert/weightless
|
||||
|
||||
@@ -108,7 +108,7 @@
|
||||
A.attack_animal(src)
|
||||
|
||||
/atom/proc/attack_animal(mob/user)
|
||||
return
|
||||
SEND_SIGNAL(src, COMSIG_ATOM_ATTACK_ANIMAL, user)
|
||||
|
||||
/mob/living/RestrainedClickOn(atom/A)
|
||||
return
|
||||
|
||||
@@ -521,3 +521,10 @@
|
||||
* Camera mobs, AIs, ghosts and some other are of course exempt from this. This also doesn't influence simplemob AI, for the best.
|
||||
*/
|
||||
/datum/config_entry/flag/use_field_of_vision
|
||||
|
||||
//Shuttle size limiter
|
||||
/datum/config_entry/number/max_shuttle_count
|
||||
config_entry_value = 6
|
||||
|
||||
/datum/config_entry/number/max_shuttle_size
|
||||
config_entry_value = 250
|
||||
|
||||
@@ -76,6 +76,8 @@ SUBSYSTEM_DEF(air)
|
||||
var/list/pipenet_rebuilds = pipenets_needing_rebuilt
|
||||
for(var/thing in pipenet_rebuilds)
|
||||
var/obj/machinery/atmospherics/AT = thing
|
||||
if(!istype(AT))
|
||||
continue
|
||||
AT.build_network()
|
||||
cost_rebuilds = MC_AVERAGE(cost_rebuilds, TICK_DELTA_TO_MS(TICK_USAGE_REAL - timer))
|
||||
pipenets_needing_rebuilt.Cut()
|
||||
|
||||
@@ -6,17 +6,7 @@ SUBSYSTEM_DEF(assets)
|
||||
var/list/preload = list()
|
||||
|
||||
/datum/controller/subsystem/assets/Initialize(timeofday)
|
||||
|
||||
var/list/priority_assets = list(
|
||||
/datum/asset/simple/oui_theme_nano,
|
||||
/datum/asset/simple/goonchat
|
||||
)
|
||||
|
||||
for(var/type in priority_assets)
|
||||
var/datum/asset/A = new type()
|
||||
A.register()
|
||||
|
||||
for(var/type in typesof(/datum/asset) - (priority_assets | list(/datum/asset, /datum/asset/simple)))
|
||||
for(var/type in typesof(/datum/asset))
|
||||
var/datum/asset/A = type
|
||||
if (type != initial(A._abstract))
|
||||
get_asset_datum(type)
|
||||
|
||||
@@ -10,24 +10,52 @@ SUBSYSTEM_DEF(materials)
|
||||
var/list/materials
|
||||
///Dictionary of category || list of material refs
|
||||
var/list/materials_by_category
|
||||
///Dictionary of category || list of material types, mostly used by rnd machines like autolathes.
|
||||
var/list/materialtypes_by_category
|
||||
///A cache of all material combinations that have been used
|
||||
var/list/list/material_combos
|
||||
///List of stackcrafting recipes for materials using rigid materials
|
||||
var/list/rigid_stack_recipes = list(
|
||||
new /datum/stack_recipe("chair", /obj/structure/chair/greyscale, one_per_turf = TRUE, on_floor = TRUE, applies_mats = TRUE),
|
||||
new /datum/stack_recipe("toilet", /obj/structure/toilet/greyscale, one_per_turf = TRUE, on_floor = TRUE, applies_mats = TRUE),
|
||||
new /datum/stack_recipe("sink", /obj/structure/sink/greyscale, one_per_turf = TRUE, on_floor = TRUE, applies_mats = TRUE),
|
||||
new /datum/stack_recipe("Floor tile", /obj/item/stack/tile/material, 1, 4, 20, applies_mats = TRUE)
|
||||
)
|
||||
|
||||
///Ran on initialize, populated the materials and materials_by_category dictionaries with their appropiate vars (See these variables for more info)
|
||||
/datum/controller/subsystem/materials/proc/InitializeMaterials()
|
||||
materials = list()
|
||||
materials_by_category = list()
|
||||
materialtypes_by_category = list()
|
||||
material_combos = list()
|
||||
for(var/type in subtypesof(/datum/material))
|
||||
var/datum/material/ref = new type
|
||||
materials[type] = ref
|
||||
for(var/c in ref.categories)
|
||||
materials_by_category[c] += list(ref)
|
||||
materialtypes_by_category[c] += list(type)
|
||||
|
||||
/datum/controller/subsystem/materials/proc/GetMaterialRef(datum/material/fakemat)
|
||||
if(!materials)
|
||||
InitializeMaterials()
|
||||
return materials[fakemat] || fakemat
|
||||
return materials[fakemat] || fakemat
|
||||
|
||||
|
||||
///Returns a list to be used as an object's custom_materials. Lists will be cached and re-used based on the parameters.
|
||||
/datum/controller/subsystem/materials/proc/FindOrCreateMaterialCombo(list/materials_declaration, multiplier)
|
||||
if(!material_combos)
|
||||
InitializeMaterials()
|
||||
var/list/combo_params = list()
|
||||
for(var/x in materials_declaration)
|
||||
var/datum/material/mat = x
|
||||
var/path_name = ispath(mat) ? "[mat]" : "[mat.type]"
|
||||
combo_params += "[path_name]=[materials_declaration[mat] * multiplier]"
|
||||
sortTim(combo_params, /proc/cmp_text_asc) // We have to sort now in case the declaration was not in order
|
||||
var/combo_index = combo_params.Join("-")
|
||||
var/list/combo = material_combos[combo_index]
|
||||
if(!combo)
|
||||
combo = list()
|
||||
for(var/mat in materials_declaration)
|
||||
combo[GetMaterialRef(mat)] = materials_declaration[mat] * multiplier
|
||||
material_combos[combo_index] = combo
|
||||
return combo
|
||||
|
||||
@@ -1,8 +1,8 @@
|
||||
SUBSYSTEM_DEF(minimaps)
|
||||
name = "Minimaps"
|
||||
flags = SS_NO_FIRE
|
||||
var/list/station_minimaps
|
||||
var/datum/minimap_group/station_minimap
|
||||
var/list/station_minimaps = list()
|
||||
var/datum/minimap_group/station_minimap = null
|
||||
|
||||
/datum/controller/subsystem/minimaps/Initialize()
|
||||
if(!CONFIG_GET(flag/minimaps_enabled))
|
||||
@@ -12,9 +12,9 @@ SUBSYSTEM_DEF(minimaps)
|
||||
return ..()
|
||||
|
||||
/datum/controller/subsystem/minimaps/proc/build_minimaps()
|
||||
station_minimaps = list()
|
||||
for(var/z in SSmapping.levels_by_trait(ZTRAIT_STATION))
|
||||
var/datum/space_level/SL = SSmapping.get_level(z)
|
||||
var/name = (SL.name == initial(SL.name))? "[z] - Station" : "[z] - [SL.name]"
|
||||
station_minimaps += new /datum/minimap(z, name = name)
|
||||
|
||||
station_minimap = new(station_minimaps, "Station")
|
||||
|
||||
@@ -23,7 +23,7 @@ SUBSYSTEM_DEF(npcpool)
|
||||
var/mob/living/simple_animal/SA = currentrun[currentrun.len]
|
||||
--currentrun.len
|
||||
|
||||
if(!SA.ckey && !SA.notransform)
|
||||
if(!SA.ckey && !SA.mob_transforming)
|
||||
if(SA.stat != DEAD)
|
||||
SA.handle_automated_movement()
|
||||
if(SA.stat != DEAD)
|
||||
|
||||
@@ -409,7 +409,7 @@ SUBSYSTEM_DEF(ticker)
|
||||
var/mob/living = player.transfer_character()
|
||||
if(living)
|
||||
qdel(player)
|
||||
living.notransform = TRUE
|
||||
living.mob_transforming = TRUE
|
||||
if(living.client)
|
||||
if (living.client.prefs && living.client.prefs.auto_ooc)
|
||||
if (living.client.prefs.chat_toggles & CHAT_OOC)
|
||||
@@ -423,7 +423,7 @@ SUBSYSTEM_DEF(ticker)
|
||||
/datum/controller/subsystem/ticker/proc/release_characters(list/livings)
|
||||
for(var/I in livings)
|
||||
var/mob/living/L = I
|
||||
L.notransform = FALSE
|
||||
L.mob_transforming = FALSE
|
||||
|
||||
/datum/controller/subsystem/ticker/proc/send_tip_of_the_round()
|
||||
var/m
|
||||
|
||||
@@ -117,6 +117,11 @@
|
||||
paralysis_type = "legs"
|
||||
resilience = TRAUMA_RESILIENCE_ABSOLUTE
|
||||
|
||||
/datum/brain_trauma/severe/paralysis/spinesnapped
|
||||
random_gain = FALSE
|
||||
paralysis_type = "legs"
|
||||
resilience = TRAUMA_RESILIENCE_LOBOTOMY
|
||||
|
||||
/datum/brain_trauma/severe/narcolepsy
|
||||
name = "Narcolepsy"
|
||||
desc = "Patient may involuntarily fall asleep during normal activities."
|
||||
|
||||
@@ -123,7 +123,9 @@
|
||||
trauma = _trauma
|
||||
return ..()
|
||||
|
||||
/mob/living/split_personality/Life()
|
||||
/mob/living/split_personality/BiologicalLife(seconds, times_fired)
|
||||
if(!(. = ..()))
|
||||
return
|
||||
if(QDELETED(body))
|
||||
qdel(src) //in case trauma deletion doesn't already do it
|
||||
|
||||
@@ -132,8 +134,6 @@
|
||||
trauma.switch_personalities()
|
||||
qdel(trauma)
|
||||
|
||||
..()
|
||||
|
||||
/mob/living/split_personality/Login()
|
||||
..()
|
||||
to_chat(src, "<span class='notice'>As a split personality, you cannot do anything but observe. However, you will eventually gain control of your body, switching places with the current personality.</span>")
|
||||
|
||||
@@ -97,20 +97,20 @@
|
||||
[get_footer()]
|
||||
"}
|
||||
|
||||
/datum/browser/proc/open(use_onclose = 1)
|
||||
/datum/browser/proc/open(use_onclose = TRUE)
|
||||
if(isnull(window_id)) //null check because this can potentially nuke goonchat
|
||||
WARNING("Browser [title] tried to open with a null ID")
|
||||
to_chat(user, "<span class='userdanger'>The [title] browser you tried to open failed a sanity check! Please report this on github!</span>")
|
||||
return
|
||||
var/window_size = ""
|
||||
if (width && height)
|
||||
if(width && height)
|
||||
window_size = "size=[width]x[height];"
|
||||
if (stylesheets.len)
|
||||
send_asset_list(user, stylesheets, verify=FALSE)
|
||||
if (scripts.len)
|
||||
send_asset_list(user, scripts, verify=FALSE)
|
||||
if(stylesheets.len)
|
||||
send_asset_list(user, stylesheets)
|
||||
if(scripts.len)
|
||||
send_asset_list(user, scripts)
|
||||
user << browse(get_content(), "window=[window_id];[window_size][window_options]")
|
||||
if (use_onclose)
|
||||
if(use_onclose)
|
||||
setup_onclose()
|
||||
|
||||
/datum/browser/proc/setup_onclose()
|
||||
@@ -157,7 +157,7 @@
|
||||
close()
|
||||
|
||||
//designed as a drop in replacement for alert(); functions the same. (outside of needing User specified)
|
||||
/proc/tgalert(var/mob/User, Message, Title, Button1="Ok", Button2, Button3, StealFocus = 1, Timeout = 6000)
|
||||
/proc/tgalert(mob/User, Message, Title, Button1="Ok", Button2, Button3, StealFocus = 1, Timeout = 6000)
|
||||
if (!User)
|
||||
User = usr
|
||||
switch(askuser(User, Message, Title, Button1, Button2, Button3, StealFocus, Timeout))
|
||||
|
||||
@@ -114,7 +114,7 @@
|
||||
// BYOND Bug #2563917
|
||||
// Construct text
|
||||
var/static/regex/html_metachars = new(@"&[A-Za-z]{1,7};", "g")
|
||||
var/complete_text = "<span class='center maptext [extra_classes.Join(" ")]' style='color: [tgt_color]'>[text]</span>"
|
||||
var/complete_text = "<span class='center maptext [extra_classes.Join(" ")]' style='color: [tgt_color]'>[owner.say_emphasis(text)]</span>"
|
||||
var/mheight = WXH_TO_HEIGHT(owned_by.MeasureText(replacetext(complete_text, html_metachars, "m"), null, CHAT_MESSAGE_WIDTH))
|
||||
approx_lines = max(1, mheight / CHAT_MESSAGE_APPROX_LHEIGHT)
|
||||
|
||||
|
||||
@@ -30,7 +30,7 @@ GLOBAL_LIST_EMPTY(cinematics)
|
||||
/datum/cinematic
|
||||
var/id = CINEMATIC_DEFAULT
|
||||
var/list/watching = list() //List of clients watching this
|
||||
var/list/locked = list() //Who had notransform set during the cinematic
|
||||
var/list/locked = list() //Who had mob_transforming set during the cinematic
|
||||
var/is_global = FALSE //Global cinematics will override mob-specific ones
|
||||
var/obj/screen/cinematic/screen
|
||||
var/datum/callback/special_callback //For special effects synced with animation (explosions after the countdown etc)
|
||||
@@ -45,7 +45,7 @@ GLOBAL_LIST_EMPTY(cinematics)
|
||||
GLOB.cinematics -= src
|
||||
QDEL_NULL(screen)
|
||||
for(var/mob/M in locked)
|
||||
M.notransform = FALSE
|
||||
M.mob_transforming = FALSE
|
||||
return ..()
|
||||
|
||||
/datum/cinematic/proc/play(watchers)
|
||||
@@ -70,7 +70,7 @@ GLOBAL_LIST_EMPTY(cinematics)
|
||||
|
||||
for(var/mob/M in GLOB.mob_list)
|
||||
if(M in watchers)
|
||||
M.notransform = TRUE //Should this be done for non-global cinematics or even at all ?
|
||||
M.mob_transforming = TRUE //Should this be done for non-global cinematics or even at all ?
|
||||
locked += M
|
||||
//Close watcher ui's
|
||||
SStgui.close_user_uis(M)
|
||||
@@ -79,7 +79,7 @@ GLOBAL_LIST_EMPTY(cinematics)
|
||||
M.client.screen += screen
|
||||
else
|
||||
if(is_global)
|
||||
M.notransform = TRUE
|
||||
M.mob_transforming = TRUE
|
||||
locked += M
|
||||
|
||||
//Actually play it
|
||||
@@ -254,4 +254,4 @@ Nuke.Explosion()
|
||||
|
||||
Narsie()
|
||||
-> Cinematic(CULT,world)
|
||||
*/
|
||||
*/
|
||||
|
||||
@@ -38,8 +38,9 @@
|
||||
parent = raw_args[1]
|
||||
var/list/arguments = raw_args.Copy(2)
|
||||
if(Initialize(arglist(arguments)) == COMPONENT_INCOMPATIBLE)
|
||||
stack_trace("Incompatible [type] assigned to a [parent.type]! args: [json_encode(arguments)]")
|
||||
qdel(src, TRUE, TRUE)
|
||||
CRASH("Incompatible [type] assigned to a [parent.type]! args: [json_encode(arguments)]")
|
||||
return
|
||||
|
||||
_JoinParent(parent)
|
||||
|
||||
|
||||
@@ -109,7 +109,7 @@
|
||||
AM.visible_message("<span class='boldwarning'>[AM] falls into [parent]!</span>", "<span class='userdanger'>[oblivion_message]</span>")
|
||||
if (isliving(AM))
|
||||
var/mob/living/L = AM
|
||||
L.notransform = TRUE
|
||||
L.mob_transforming = TRUE
|
||||
L.Paralyze(200)
|
||||
|
||||
var/oldtransform = AM.transform
|
||||
|
||||
@@ -124,9 +124,9 @@
|
||||
category = CAT_MISC
|
||||
subcategory = CAT_TOOL
|
||||
|
||||
/datum/crafting_recipe/bruise_pack
|
||||
name = "Bruise Pack"
|
||||
result = /obj/item/stack/medical/bruise_pack/one
|
||||
/datum/crafting_recipe/brute_pack
|
||||
name = "Suture Pack"
|
||||
result = /obj/item/stack/medical/suture/one
|
||||
time = 1
|
||||
reqs = list(/obj/item/stack/medical/gauze = 1,
|
||||
/datum/reagent/medicine/styptic_powder = 10)
|
||||
@@ -134,8 +134,8 @@
|
||||
subcategory = CAT_TOOL
|
||||
|
||||
/datum/crafting_recipe/burn_pack
|
||||
name = "Burn Ointment"
|
||||
result = /obj/item/stack/medical/ointment/one
|
||||
name = "Regenerative Mesh"
|
||||
result = /obj/item/stack/medical/mesh/one
|
||||
time = 1
|
||||
reqs = list(/obj/item/stack/medical/gauze = 1,
|
||||
/datum/reagent/medicine/silver_sulfadiazine = 10)
|
||||
|
||||
@@ -0,0 +1,244 @@
|
||||
/*!
|
||||
This component makes it possible to make things edible. What this means is that you can take a bite or force someone to take a bite (in the case of items).
|
||||
These items take a specific time to eat, and can do most of the things our original food items could.
|
||||
Behavior that's still missing from this component that original food items had that should either be put into seperate components or somewhere else:
|
||||
Components:
|
||||
Drying component (jerky etc)
|
||||
Customizable component (custom pizzas etc)
|
||||
Processable component (Slicing and cooking behavior essentialy, making it go from item A to B when conditions are met.)
|
||||
Dunkable component (Dunking things into reagent containers to absorb a specific amount of reagents)
|
||||
Misc:
|
||||
Something for cakes (You can store things inside)
|
||||
*/
|
||||
/datum/component/edible
|
||||
///Amount of reagents taken per bite
|
||||
var/bite_consumption = 2
|
||||
///Amount of bites taken so far
|
||||
var/bitecount = 0
|
||||
///Flags for food
|
||||
var/food_flags = NONE
|
||||
///Bitfield of the types of this food
|
||||
var/foodtypes = NONE
|
||||
///Amount of seconds it takes to eat this food
|
||||
var/eat_time = 30
|
||||
///Defines how much it lowers someones satiety (Need to eat, essentialy)
|
||||
var/junkiness = 0
|
||||
///Message to send when eating
|
||||
var/list/eatverbs
|
||||
///Callback to be ran for when you take a bite of something
|
||||
var/datum/callback/after_eat
|
||||
///Last time we checked for food likes
|
||||
var/last_check_time
|
||||
|
||||
/datum/component/edible/Initialize(list/initial_reagents, food_flags = NONE, foodtypes = NONE, volume = 50, eat_time = 30, list/tastes, list/eatverbs = list("bite","chew","nibble","gnaw","gobble","chomp"), bite_consumption = 2, datum/callback/after_eat)
|
||||
if(!isatom(parent))
|
||||
return COMPONENT_INCOMPATIBLE
|
||||
|
||||
RegisterSignal(parent, COMSIG_PARENT_EXAMINE, .proc/examine)
|
||||
RegisterSignal(parent, COMSIG_ATOM_ATTACK_ANIMAL, .proc/UseByAnimal)
|
||||
if(isitem(parent))
|
||||
RegisterSignal(parent, COMSIG_ITEM_ATTACK, .proc/UseFromHand)
|
||||
else if(isturf(parent))
|
||||
RegisterSignal(parent, COMSIG_ATOM_ATTACK_HAND, .proc/TryToEatTurf)
|
||||
|
||||
src.bite_consumption = bite_consumption
|
||||
src.food_flags = food_flags
|
||||
src.foodtypes = foodtypes
|
||||
src.eat_time = eat_time
|
||||
src.eatverbs = eatverbs
|
||||
src.junkiness = junkiness
|
||||
src.after_eat = after_eat
|
||||
|
||||
var/atom/owner = parent
|
||||
|
||||
owner.create_reagents(volume, INJECTABLE)
|
||||
|
||||
if(initial_reagents)
|
||||
for(var/rid in initial_reagents)
|
||||
var/amount = initial_reagents[rid]
|
||||
if(tastes && tastes.len && (rid == /datum/reagent/consumable/nutriment || rid == /datum/reagent/consumable/nutriment/vitamin))
|
||||
owner.reagents.add_reagent(rid, amount, tastes.Copy())
|
||||
else
|
||||
owner.reagents.add_reagent(rid, amount)
|
||||
|
||||
/datum/component/edible/proc/examine(datum/source, mob/user, list/examine_list)
|
||||
if(!(food_flags & FOOD_IN_CONTAINER))
|
||||
switch (bitecount)
|
||||
if (0)
|
||||
return
|
||||
if(1)
|
||||
examine_list += "[parent] was bitten by someone!"
|
||||
if(2,3)
|
||||
examine_list += "[parent] was bitten [bitecount] times!"
|
||||
else
|
||||
examine_list += "[parent] was bitten multiple times!"
|
||||
|
||||
/datum/component/edible/proc/UseFromHand(obj/item/source, mob/living/M, mob/living/user)
|
||||
return TryToEat(M, user)
|
||||
|
||||
/datum/component/edible/proc/TryToEatTurf(datum/source, mob/user)
|
||||
return TryToEat(user, user)
|
||||
|
||||
///All the checks for the act of eating itself and
|
||||
/datum/component/edible/proc/TryToEat(mob/living/eater, mob/living/feeder)
|
||||
|
||||
set waitfor = FALSE
|
||||
|
||||
var/atom/owner = parent
|
||||
|
||||
if(feeder.a_intent == INTENT_HARM)
|
||||
return
|
||||
if(!owner.reagents.total_volume)//Shouldn't be needed but it checks to see if it has anything left in it.
|
||||
to_chat(feeder, "<span class='warning'>None of [owner] left, oh no!</span>")
|
||||
if(isturf(parent))
|
||||
var/turf/T = parent
|
||||
T.ScrapeAway(1, CHANGETURF_INHERIT_AIR)
|
||||
else
|
||||
qdel(parent)
|
||||
return
|
||||
if(!CanConsume(eater, feeder))
|
||||
return
|
||||
var/fullness = eater.nutrition + 10 //The theoretical fullness of the person eating if they were to eat this
|
||||
for(var/datum/reagent/consumable/C in eater.reagents.reagent_list) //we add the nutrition value of what we're currently digesting
|
||||
fullness += C.nutriment_factor * C.volume / C.metabolization_rate
|
||||
|
||||
. = COMPONENT_ITEM_NO_ATTACK //Point of no return I suppose
|
||||
|
||||
if(eater == feeder)//If you're eating it yourself.
|
||||
if(!do_mob(feeder, eater, eat_time)) //Gotta pass the minimal eat time
|
||||
return
|
||||
var/eatverb = pick(eatverbs)
|
||||
if(junkiness && eater.satiety < -150 && eater.nutrition > NUTRITION_LEVEL_STARVING + 50 && !HAS_TRAIT(eater, TRAIT_VORACIOUS))
|
||||
to_chat(eater, "<span class='warning'>You don't feel like eating any more junk food at the moment!</span>")
|
||||
return
|
||||
else if(fullness <= 50)
|
||||
eater.visible_message("<span class='notice'>[eater] hungrily [eatverb]s \the [parent], gobbling it down!</span>", "<span class='notice'>You hungrily [eatverb] \the [parent], gobbling it down!</span>")
|
||||
else if(fullness > 50 && fullness < 150)
|
||||
eater.visible_message("<span class='notice'>[eater] hungrily [eatverb]s \the [parent].</span>", "<span class='notice'>You hungrily [eatverb] \the [parent].</span>")
|
||||
else if(fullness > 150 && fullness < 500)
|
||||
eater.visible_message("<span class='notice'>[eater] [eatverb]s \the [parent].</span>", "<span class='notice'>You [eatverb] \the [parent].</span>")
|
||||
else if(fullness > 500 && fullness < 600)
|
||||
eater.visible_message("<span class='notice'>[eater] unwillingly [eatverb]s a bit of \the [parent].</span>", "<span class='notice'>You unwillingly [eatverb] a bit of \the [parent].</span>")
|
||||
else if(fullness > (600 * (1 + eater.overeatduration / 2000))) // The more you eat - the more you can eat
|
||||
eater.visible_message("<span class='warning'>[eater] cannot force any more of \the [parent] to go down [eater.p_their()] throat!</span>", "<span class='warning'>You cannot force any more of \the [parent] to go down your throat!</span>")
|
||||
return
|
||||
else //If you're feeding it to someone else.
|
||||
if(isbrain(eater))
|
||||
to_chat(feeder, "<span class='warning'>[eater] doesn't seem to have a mouth!</span>")
|
||||
return
|
||||
if(fullness <= (600 * (1 + eater.overeatduration / 1000)))
|
||||
eater.visible_message("<span class='danger'>[feeder] attempts to feed [eater] [parent].</span>", \
|
||||
"<span class='userdanger'>[feeder] attempts to feed you [parent].</span>")
|
||||
else
|
||||
eater.visible_message("<span class='warning'>[feeder] cannot force any more of [parent] down [eater]'s throat!</span>", \
|
||||
"<span class='warning'>[feeder] cannot force any more of [parent] down your throat!</span>")
|
||||
return
|
||||
if(!do_mob(feeder, eater)) //Wait 3 seconds before you can feed
|
||||
return
|
||||
|
||||
log_combat(feeder, eater, "fed", owner.reagents.log_list())
|
||||
eater.visible_message("<span class='danger'>[feeder] forces [eater] to eat [parent]!</span>", \
|
||||
"<span class='userdanger'>[feeder] forces you to eat [parent]!</span>")
|
||||
|
||||
TakeBite(eater, feeder)
|
||||
|
||||
///This function lets the eater take a bite and transfers the reagents to the eater.
|
||||
/datum/component/edible/proc/TakeBite(mob/living/eater, mob/living/feeder)
|
||||
|
||||
var/atom/owner = parent
|
||||
|
||||
if(!owner?.reagents)
|
||||
return FALSE
|
||||
if(eater.satiety > -200)
|
||||
eater.satiety -= junkiness
|
||||
playsound(eater.loc,'sound/items/eatfood.ogg', rand(10,50), TRUE)
|
||||
if(owner.reagents.total_volume)
|
||||
SEND_SIGNAL(parent, COMSIG_FOOD_EATEN, eater, feeder)
|
||||
var/fraction = min(bite_consumption / owner.reagents.total_volume, 1)
|
||||
owner.reagents.reaction(eater, INGEST, fraction)
|
||||
owner.reagents.trans_to(eater, bite_consumption)
|
||||
bitecount++
|
||||
On_Consume(eater)
|
||||
checkLiked(fraction, eater)
|
||||
|
||||
//Invoke our after eat callback if it is valid
|
||||
if(after_eat)
|
||||
after_eat.Invoke(eater, feeder)
|
||||
|
||||
return TRUE
|
||||
|
||||
///Checks whether or not the eater can actually consume the food
|
||||
/datum/component/edible/proc/CanConsume(mob/living/eater, mob/living/feeder)
|
||||
if(!iscarbon(eater))
|
||||
return FALSE
|
||||
var/mob/living/carbon/C = eater
|
||||
var/covered = ""
|
||||
if(C.is_mouth_covered(head_only = 1))
|
||||
covered = "headgear"
|
||||
else if(C.is_mouth_covered(mask_only = 1))
|
||||
covered = "mask"
|
||||
if(covered)
|
||||
var/who = (isnull(feeder) || eater == feeder) ? "your" : "[eater.p_their()]"
|
||||
to_chat(feeder, "<span class='warning'>You have to remove [who] [covered] first!</span>")
|
||||
return FALSE
|
||||
return TRUE
|
||||
|
||||
///Check foodtypes to see if we should send a moodlet
|
||||
/datum/component/edible/proc/checkLiked(var/fraction, mob/M)
|
||||
if(last_check_time + 50 > world.time)
|
||||
return FALSE
|
||||
if(!ishuman(M))
|
||||
return FALSE
|
||||
var/mob/living/carbon/human/H = M
|
||||
if(HAS_TRAIT(H, TRAIT_AGEUSIA) && foodtypes & H.dna.species.toxic_food)
|
||||
to_chat(H, "<span class='warning'>You don't feel so good...</span>")
|
||||
H.adjust_disgust(25 + 30 * fraction)
|
||||
else
|
||||
if(foodtypes & H.dna.species.toxic_food)
|
||||
to_chat(H,"<span class='warning'>What the hell was that thing?!</span>")
|
||||
H.adjust_disgust(25 + 30 * fraction)
|
||||
SEND_SIGNAL(H, COMSIG_ADD_MOOD_EVENT, "toxic_food", /datum/mood_event/disgusting_food)
|
||||
else if(foodtypes & H.dna.species.disliked_food)
|
||||
to_chat(H,"<span class='notice'>That didn't taste very good...</span>")
|
||||
H.adjust_disgust(11 + 15 * fraction)
|
||||
SEND_SIGNAL(H, COMSIG_ADD_MOOD_EVENT, "gross_food", /datum/mood_event/gross_food)
|
||||
else if(foodtypes & H.dna.species.liked_food)
|
||||
to_chat(H,"<span class='notice'>I love this taste!</span>")
|
||||
H.adjust_disgust(-5 + -2.5 * fraction)
|
||||
SEND_SIGNAL(H, COMSIG_ADD_MOOD_EVENT, "fav_food", /datum/mood_event/favorite_food)
|
||||
if((foodtypes & BREAKFAST) && world.time - SSticker.round_start_time < STOP_SERVING_BREAKFAST)
|
||||
SEND_SIGNAL(H, COMSIG_ADD_MOOD_EVENT, "breakfast", /datum/mood_event/breakfast)
|
||||
last_check_time = world.time
|
||||
|
||||
///Delete the item when it is fully eaten
|
||||
/datum/component/edible/proc/On_Consume(mob/living/eater)
|
||||
|
||||
var/atom/owner = parent
|
||||
|
||||
if(!eater)
|
||||
return
|
||||
if(!owner.reagents.total_volume)
|
||||
if(isturf(parent))
|
||||
var/turf/T = parent
|
||||
T.ScrapeAway(1, CHANGETURF_INHERIT_AIR)
|
||||
else
|
||||
qdel(parent)
|
||||
|
||||
///Ability to feed food to puppers
|
||||
/datum/component/edible/proc/UseByAnimal(datum/source, mob/user)
|
||||
|
||||
var/atom/owner = parent
|
||||
|
||||
if(!isdog(user))
|
||||
return
|
||||
var/mob/living/L = user
|
||||
if(bitecount == 0 || prob(50))
|
||||
L.emote("me", 1, "nibbles away at \the [parent]")
|
||||
bitecount++
|
||||
. = COMPONENT_ITEM_NO_ATTACK
|
||||
L.taste(owner.reagents) // why should carbons get all the fun?
|
||||
if(bitecount >= 5)
|
||||
var/sattisfaction_text = pick("burps from enjoyment", "yaps for more", "woofs twice", "looks at the area where \the [parent] was")
|
||||
if(sattisfaction_text)
|
||||
L.emote("me", 1, "[sattisfaction_text]")
|
||||
qdel(parent)
|
||||
@@ -0,0 +1,363 @@
|
||||
/*
|
||||
This component is responsible for handling individual instances of embedded objects. The embeddable element is what allows an item to be embeddable and stores its embedding stats,
|
||||
and when it impacts and meets the requirements to stick into something, it instantiates an embedded component. Once the item falls out, the component is destroyed, while the
|
||||
element survives to embed another day.
|
||||
|
||||
There are 2 different things that can be embedded presently: carbons, and closed turfs (see: walls)
|
||||
|
||||
- Carbon embedding has all the classical embedding behavior, and tracks more events and signals. The main behaviors and hooks to look for are:
|
||||
-- Every process tick, there is a chance to randomly proc pain, controlled by pain_chance. There may also be a chance for the object to fall out randomly, per fall_chance
|
||||
-- Every time the mob moves, there is a chance to proc jostling pain, controlled by jostle_chance (and only 50% as likely if the mob is walking or crawling)
|
||||
-- Various signals hooking into carbon topic() and the embed removal surgery in order to handle removals.
|
||||
|
||||
- Turf embedding is much simpler. All we do here is draw an overlay of the item's inhand on the turf, hide the item, and create an HTML link in the turf's inspect
|
||||
that allows you to rip the item out. There's nothing dynamic about this, so far less checks.
|
||||
|
||||
|
||||
In addition, there are 2 cases of embedding: embedding, and sticking
|
||||
|
||||
- Embedding involves harmful and dangerous embeds, whether they cause brute damage, stamina damage, or a mix. This is the default behavior for embeddings, for when something is "pointy"
|
||||
|
||||
- Sticking occurs when an item should not cause any harm while embedding (imagine throwing a sticky ball of tape at someone, rather than a shuriken). An item is considered "sticky"
|
||||
when it has 0 for both pain multiplier and jostle pain multiplier. It's a bit arbitrary, but fairly straightforward.
|
||||
|
||||
Stickables differ from embeds in the following ways:
|
||||
-- Text descriptors use phrasing like "X is stuck to Y" rather than "X is embedded in Y"
|
||||
-- There is no slicing sound on impact
|
||||
-- All damage checks and bloodloss are skipped for carbons
|
||||
-- Pointy objects create sparks when embedding into a turf
|
||||
|
||||
*/
|
||||
|
||||
|
||||
/datum/component/embedded
|
||||
dupe_mode = COMPONENT_DUPE_ALLOWED
|
||||
var/obj/item/bodypart/limb
|
||||
var/obj/item/weapon
|
||||
|
||||
// all of this stuff is explained in _DEFINES/combat.dm
|
||||
var/embed_chance // not like we really need it once we're already stuck in but hey
|
||||
var/fall_chance
|
||||
var/pain_chance
|
||||
var/pain_mult
|
||||
var/impact_pain_mult
|
||||
var/remove_pain_mult
|
||||
var/rip_time
|
||||
var/ignore_throwspeed_threshold
|
||||
var/jostle_chance
|
||||
var/jostle_pain_mult
|
||||
var/pain_stam_pct
|
||||
var/embed_chance_turf_mod
|
||||
|
||||
///if both our pain multiplier and jostle pain multiplier are 0, we're harmless and can omit most of the damage related stuff
|
||||
var/harmful
|
||||
var/mutable_appearance/overlay
|
||||
|
||||
/datum/component/embedded/Initialize(obj/item/I,
|
||||
datum/thrownthing/throwingdatum,
|
||||
obj/item/bodypart/part,
|
||||
embed_chance = EMBED_CHANCE,
|
||||
fall_chance = EMBEDDED_ITEM_FALLOUT,
|
||||
pain_chance = EMBEDDED_PAIN_CHANCE,
|
||||
pain_mult = EMBEDDED_PAIN_MULTIPLIER,
|
||||
remove_pain_mult = EMBEDDED_UNSAFE_REMOVAL_PAIN_MULTIPLIER,
|
||||
impact_pain_mult = EMBEDDED_IMPACT_PAIN_MULTIPLIER,
|
||||
rip_time = EMBEDDED_UNSAFE_REMOVAL_TIME,
|
||||
ignore_throwspeed_threshold = FALSE,
|
||||
jostle_chance = EMBEDDED_JOSTLE_CHANCE,
|
||||
jostle_pain_mult = EMBEDDED_JOSTLE_PAIN_MULTIPLIER,
|
||||
pain_stam_pct = EMBEDDED_PAIN_STAM_PCT,
|
||||
embed_chance_turf_mod = EMBED_CHANCE_TURF_MOD)
|
||||
|
||||
if((!iscarbon(parent) && !isclosedturf(parent)) || !isitem(I))
|
||||
return COMPONENT_INCOMPATIBLE
|
||||
|
||||
if(part)
|
||||
limb = part
|
||||
src.embed_chance = embed_chance
|
||||
src.fall_chance = fall_chance
|
||||
src.pain_chance = pain_chance
|
||||
src.pain_mult = pain_mult
|
||||
src.remove_pain_mult = remove_pain_mult
|
||||
src.rip_time = rip_time
|
||||
src.impact_pain_mult = impact_pain_mult
|
||||
src.ignore_throwspeed_threshold = ignore_throwspeed_threshold
|
||||
src.jostle_chance = jostle_chance
|
||||
src.jostle_pain_mult = jostle_pain_mult
|
||||
src.pain_stam_pct = pain_stam_pct
|
||||
src.embed_chance_turf_mod = embed_chance_turf_mod
|
||||
|
||||
src.weapon = I
|
||||
|
||||
if(!weapon.isEmbedHarmless())
|
||||
harmful = TRUE
|
||||
|
||||
weapon.embedded(parent)
|
||||
|
||||
if(iscarbon(parent))
|
||||
initCarbon()
|
||||
else if(isclosedturf(parent))
|
||||
initTurf(throwingdatum)
|
||||
|
||||
/datum/component/embedded/RegisterWithParent()
|
||||
if(iscarbon(parent))
|
||||
RegisterSignal(parent, COMSIG_MOVABLE_MOVED, .proc/jostleCheck)
|
||||
RegisterSignal(parent, COMSIG_CARBON_EMBED_RIP, .proc/ripOutCarbon)
|
||||
RegisterSignal(parent, COMSIG_CARBON_EMBED_REMOVAL, .proc/safeRemoveCarbon)
|
||||
else if(isclosedturf(parent))
|
||||
RegisterSignal(parent, COMSIG_PARENT_EXAMINE, .proc/examineTurf)
|
||||
RegisterSignal(parent, COMSIG_PARENT_QDELETING, .proc/itemMoved)
|
||||
|
||||
/datum/component/embedded/UnregisterFromParent()
|
||||
UnregisterSignal(parent, list(COMSIG_MOVABLE_MOVED, COMSIG_CARBON_EMBED_RIP, COMSIG_CARBON_EMBED_REMOVAL, COMSIG_PARENT_EXAMINE))
|
||||
|
||||
/datum/component/embedded/process()
|
||||
if(iscarbon(parent))
|
||||
processCarbon()
|
||||
|
||||
/datum/component/embedded/Destroy()
|
||||
if(weapon)
|
||||
UnregisterSignal(weapon, list(COMSIG_MOVABLE_MOVED, COMSIG_PARENT_QDELETING))
|
||||
if(overlay)
|
||||
var/atom/A = parent
|
||||
A.cut_overlay(overlay, TRUE)
|
||||
qdel(overlay)
|
||||
|
||||
return ..()
|
||||
|
||||
////////////////////////////////////////
|
||||
/////////////HUMAN PROCS////////////////
|
||||
////////////////////////////////////////
|
||||
|
||||
/// Set up an instance of embedding for a carbon. This is basically an extension of Initialize() so not much to say
|
||||
/datum/component/embedded/proc/initCarbon()
|
||||
START_PROCESSING(SSdcs, src)
|
||||
var/mob/living/carbon/victim = parent
|
||||
if(!istype(limb))
|
||||
limb = pick(victim.bodyparts)
|
||||
|
||||
limb.embedded_objects |= weapon // on the inside... on the inside...
|
||||
weapon.forceMove(victim)
|
||||
RegisterSignal(weapon, list(COMSIG_MOVABLE_MOVED, COMSIG_PARENT_QDELETING), .proc/byeItemCarbon)
|
||||
|
||||
if(harmful)
|
||||
victim.visible_message("<span class='danger'>[weapon] embeds itself in [victim]'s [limb.name]!</span>",ignored_mobs=victim)
|
||||
to_chat(victim, "<span class='userdanger'>[weapon] embeds itself in your [limb.name]!</span>")
|
||||
victim.throw_alert("embeddedobject", /obj/screen/alert/embeddedobject)
|
||||
playsound(victim,'sound/weapons/bladeslice.ogg', 40)
|
||||
weapon.add_mob_blood(victim)//it embedded itself in you, of course it's bloody!
|
||||
var/damage = weapon.w_class * impact_pain_mult
|
||||
limb.receive_damage(brute=(1-pain_stam_pct) * damage, stamina=pain_stam_pct * damage)
|
||||
SEND_SIGNAL(victim, COMSIG_ADD_MOOD_EVENT, "embedded", /datum/mood_event/embedded)
|
||||
else
|
||||
victim.visible_message("<span class='danger'>[weapon] sticks itself to [victim]'s [limb.name]!</span>",ignored_mobs=victim)
|
||||
to_chat(victim, "<span class='userdanger'>[weapon] sticks itself to your [limb.name]!</span>")
|
||||
|
||||
/// Called every time a carbon with a harmful embed moves, rolling a chance for the item to cause pain. The chance is halved if the carbon is crawling or walking.
|
||||
/datum/component/embedded/proc/jostleCheck()
|
||||
var/mob/living/carbon/victim = parent
|
||||
|
||||
var/chance = jostle_chance
|
||||
if(victim.m_intent == MOVE_INTENT_WALK || !(victim.mobility_flags & MOBILITY_STAND))
|
||||
chance *= 0.5
|
||||
|
||||
if(harmful && prob(chance))
|
||||
var/damage = weapon.w_class * jostle_pain_mult
|
||||
limb.receive_damage(brute=(1-pain_stam_pct) * damage, stamina=pain_stam_pct * damage)
|
||||
to_chat(victim, "<span class='userdanger'>[weapon] embedded in your [limb.name] jostles and stings!</span>")
|
||||
|
||||
|
||||
/// Called when then item randomly falls out of a carbon. This handles the damage and descriptors, then calls safe_remove()
|
||||
/datum/component/embedded/proc/fallOutCarbon()
|
||||
var/mob/living/carbon/victim = parent
|
||||
|
||||
if(harmful)
|
||||
var/damage = weapon.w_class * remove_pain_mult
|
||||
limb.receive_damage(brute=(1-pain_stam_pct) * damage, stamina=pain_stam_pct * damage)
|
||||
victim.visible_message("<span class='danger'>[weapon] falls out of [victim.name]'s [limb.name]!</span>", ignored_mobs=victim)
|
||||
to_chat(victim, "<span class='userdanger'>[weapon] falls out of your [limb.name]!</span>")
|
||||
else
|
||||
victim.visible_message("<span class='danger'>[weapon] falls off of [victim.name]'s [limb.name]!</span>", ignored_mobs=victim)
|
||||
to_chat(victim, "<span class='userdanger'>[weapon] falls off of your [limb.name]!</span>")
|
||||
|
||||
safeRemoveCarbon()
|
||||
|
||||
|
||||
/// Called when a carbon with an object embedded/stuck to them inspects themselves and clicks the appropriate link to begin ripping the item out. This handles the ripping attempt, descriptors, and dealing damage, then calls safe_remove()
|
||||
/datum/component/embedded/proc/ripOutCarbon(datum/source, obj/item/I, obj/item/bodypart/limb)
|
||||
if(I != weapon || src.limb != limb)
|
||||
return
|
||||
|
||||
var/mob/living/carbon/victim = parent
|
||||
var/time_taken = rip_time * weapon.w_class
|
||||
|
||||
victim.visible_message("<span class='warning'>[victim] attempts to remove [weapon] from [victim.p_their()] [limb.name].</span>","<span class='notice'>You attempt to remove [weapon] from your [limb.name]... (It will take [DisplayTimeText(time_taken)].)</span>")
|
||||
if(do_after(victim, time_taken, target = victim))
|
||||
if(!weapon || !limb || weapon.loc != victim || !(weapon in limb.embedded_objects))
|
||||
qdel(src)
|
||||
return
|
||||
|
||||
if(harmful)
|
||||
var/damage = weapon.w_class * remove_pain_mult
|
||||
limb.receive_damage(brute=(1-pain_stam_pct) * damage, stamina=pain_stam_pct * damage) //It hurts to rip it out, get surgery you dingus.
|
||||
victim.emote("scream")
|
||||
victim.visible_message("<span class='notice'>[victim] successfully rips [weapon] out of [victim.p_their()] [limb.name]!</span>", "<span class='notice'>You successfully remove [weapon] from your [limb.name].</span>")
|
||||
else
|
||||
victim.visible_message("<span class='notice'>[victim] successfully rips [weapon] off of [victim.p_their()] [limb.name]!</span>", "<span class='notice'>You successfully remove [weapon] from your [limb.name].</span>")
|
||||
|
||||
safeRemoveCarbon(TRUE)
|
||||
|
||||
|
||||
/// This proc handles the final step and actual removal of an embedded/stuck item from a carbon, whether or not it was actually removed safely.
|
||||
/// Pass TRUE for to_hands if we want it to go to the victim's hands when they pull it out
|
||||
/datum/component/embedded/proc/safeRemoveCarbon(to_hands)
|
||||
var/mob/living/carbon/victim = parent
|
||||
limb.embedded_objects -= weapon
|
||||
|
||||
UnregisterSignal(weapon, list(COMSIG_MOVABLE_MOVED, COMSIG_PARENT_QDELETING)) // have to unhook these here so they don't also register as having disappeared
|
||||
|
||||
if(!weapon)
|
||||
if(!victim.has_embedded_objects())
|
||||
victim.clear_alert("embeddedobject")
|
||||
SEND_SIGNAL(victim, COMSIG_CLEAR_MOOD_EVENT, "embedded")
|
||||
qdel(src)
|
||||
return
|
||||
|
||||
if(weapon.unembedded()) // if it deleted itself
|
||||
weapon = null
|
||||
if(!victim.has_embedded_objects())
|
||||
victim.clear_alert("embeddedobject")
|
||||
SEND_SIGNAL(victim, COMSIG_CLEAR_MOOD_EVENT, "embedded")
|
||||
qdel(src)
|
||||
return
|
||||
|
||||
if(to_hands)
|
||||
victim.put_in_hands(weapon)
|
||||
else
|
||||
weapon.forceMove(get_turf(victim))
|
||||
|
||||
if(!victim.has_embedded_objects())
|
||||
victim.clear_alert("embeddedobject")
|
||||
SEND_SIGNAL(victim, COMSIG_CLEAR_MOOD_EVENT, "embedded")
|
||||
qdel(src)
|
||||
|
||||
|
||||
/// Something deleted or moved our weapon while it was embedded, how rude!
|
||||
/datum/component/embedded/proc/byeItemCarbon()
|
||||
var/mob/living/carbon/victim = parent
|
||||
limb.embedded_objects -= weapon
|
||||
UnregisterSignal(weapon, list(COMSIG_MOVABLE_MOVED, COMSIG_PARENT_QDELETING))
|
||||
|
||||
if(victim)
|
||||
to_chat(victim, "<span class='userdanger'>\The [weapon] that was embedded in your [limb.name] disappears!</span>")
|
||||
if(!victim.has_embedded_objects())
|
||||
victim.clear_alert("embeddedobject")
|
||||
SEND_SIGNAL(victim, COMSIG_CLEAR_MOOD_EVENT, "embedded")
|
||||
weapon = null
|
||||
qdel(src)
|
||||
|
||||
|
||||
/// Items embedded/stuck to carbons both check whether they randomly fall out (if applicable), as well as if the target mob and limb still exists.
|
||||
/// Items harmfully embedded in carbons have an additional check for random pain (if applicable)
|
||||
/datum/component/embedded/proc/processCarbon()
|
||||
var/mob/living/carbon/victim = parent
|
||||
|
||||
if(!victim || !limb) // in case the victim and/or their limbs exploded (say, due to a sticky bomb)
|
||||
weapon.forceMove(get_turf(weapon))
|
||||
qdel(src)
|
||||
|
||||
if(victim.stat == DEAD)
|
||||
return
|
||||
|
||||
var/damage = weapon.w_class * pain_mult
|
||||
var/chance = pain_chance
|
||||
if(pain_stam_pct && IS_STAMCRIT(victim)) //if it's a less-lethal embed, give them a break if they're already stamcritted
|
||||
chance *= 0.3
|
||||
damage *= 0.7
|
||||
|
||||
if(harmful && prob(chance))
|
||||
limb.receive_damage(brute=(1-pain_stam_pct) * damage, stamina=pain_stam_pct * damage)
|
||||
to_chat(victim, "<span class='userdanger'>[weapon] embedded in your [limb.name] hurts!</span>")
|
||||
|
||||
if(prob(fall_chance))
|
||||
fallOutCarbon()
|
||||
|
||||
|
||||
|
||||
////////////////////////////////////////
|
||||
//////////////TURF PROCS////////////////
|
||||
////////////////////////////////////////
|
||||
|
||||
/// Turfs are much lower maintenance, since we don't care if they're in pain, but since they don't bleed or scream, we draw an overlay to show their status.
|
||||
/// The only difference pointy/sticky items make here is text descriptors and pointy objects making a spark shower on impact.
|
||||
/datum/component/embedded/proc/initTurf(datum/thrownthing/throwingdatum)
|
||||
var/turf/closed/hit = parent
|
||||
|
||||
// we can't store the item IN the turf (cause turfs are just kinda... there), so we fake it by making the item invisible and bailing if it moves due to a blast
|
||||
weapon.forceMove(hit)
|
||||
weapon.invisibility = INVISIBILITY_ABSTRACT
|
||||
RegisterSignal(weapon, COMSIG_MOVABLE_MOVED, .proc/itemMoved)
|
||||
|
||||
var/pixelX = rand(-2, 2)
|
||||
var/pixelY = rand(-1, 3) // bias this upwards since in-hands are usually on the lower end of the sprite
|
||||
|
||||
switch(throwingdatum.init_dir)
|
||||
if(NORTH)
|
||||
pixelY -= 2
|
||||
if(SOUTH)
|
||||
pixelY += 2
|
||||
if(WEST)
|
||||
pixelX += 2
|
||||
if(EAST)
|
||||
pixelX -= 2
|
||||
|
||||
if(throwingdatum.init_dir in list(NORTH, WEST, NORTHWEST, SOUTHWEST))
|
||||
overlay = mutable_appearance(icon=weapon.righthand_file,icon_state=weapon.item_state)
|
||||
else
|
||||
overlay = mutable_appearance(icon=weapon.lefthand_file,icon_state=weapon.item_state)
|
||||
|
||||
var/matrix/M = matrix()
|
||||
M.Translate(pixelX, pixelY)
|
||||
overlay.transform = M
|
||||
hit.add_overlay(overlay, TRUE)
|
||||
|
||||
if(harmful)
|
||||
hit.visible_message("<span class='danger'>[weapon] embeds itself in [hit]!</span>")
|
||||
playsound(hit,'sound/weapons/bladeslice.ogg', 70)
|
||||
|
||||
var/datum/effect_system/spark_spread/sparks = new
|
||||
sparks.set_up(1, 1, parent)
|
||||
sparks.attach(parent)
|
||||
sparks.start()
|
||||
else
|
||||
hit.visible_message("<span class='danger'>[weapon] sticks itself to [hit]!</span>")
|
||||
|
||||
|
||||
/datum/component/embedded/proc/examineTurf(datum/source, mob/user, list/examine_list)
|
||||
if(harmful)
|
||||
examine_list += "\t <a href='?src=[REF(src)];embedded_object=[REF(weapon)]' class='warning'>There is \a [weapon] embedded in [parent]!</a>"
|
||||
else
|
||||
examine_list += "\t <a href='?src=[REF(src)];embedded_object=[REF(weapon)]' class='warning'>There is \a [weapon] stuck to [parent]!</a>"
|
||||
|
||||
|
||||
/// Someone is ripping out the item from the turf by hand
|
||||
/datum/component/embedded/Topic(datum/source, href_list)
|
||||
var/mob/living/us = usr
|
||||
if(in_range(us, parent) && locate(href_list["embedded_object"]) == weapon)
|
||||
if(harmful)
|
||||
us.visible_message("<span class='notice'>[us] begins unwedging [weapon] from [parent].</span>", "<span class='notice'>You begin unwedging [weapon] from [parent]...</span>")
|
||||
else
|
||||
us.visible_message("<span class='notice'>[us] begins unsticking [weapon] from [parent].</span>", "<span class='notice'>You begin unsticking [weapon] from [parent]...</span>")
|
||||
|
||||
if(do_after(us, 30, target = parent))
|
||||
us.put_in_hands(weapon)
|
||||
weapon.unembedded()
|
||||
qdel(src)
|
||||
|
||||
|
||||
/// This proc handles if something knocked the invisible item loose from the turf somehow (probably an explosion). Just make it visible and say it fell loose, then get outta here.
|
||||
/datum/component/embedded/proc/itemMoved()
|
||||
weapon.invisibility = initial(weapon.invisibility)
|
||||
weapon.visible_message("<span class='notice'>[weapon] falls loose from [parent].</span>")
|
||||
weapon.unembedded()
|
||||
qdel(src)
|
||||
@@ -144,7 +144,7 @@
|
||||
var/obj/item/projectile/picked_projectiletype = pickweight(weighted_projectile_types)
|
||||
|
||||
var/obj/item/master = comp.parent
|
||||
comp.appliedComponents += master.AddComponent(/datum/component/shrapnel, picked_projectiletype)
|
||||
comp.appliedComponents += master.AddComponent(/datum/component/mirv, picked_projectiletype)
|
||||
return "[newName] of [initial(picked_projectiletype.name)] shrapnel"
|
||||
|
||||
/datum/fantasy_affix/strength
|
||||
|
||||
@@ -1,36 +1,37 @@
|
||||
|
||||
/datum/component/shrapnel
|
||||
/datum/component/mirv
|
||||
var/projectile_type
|
||||
var/radius // shoots a projectile for every turf on this radius from the hit target
|
||||
var/override_projectile_range
|
||||
|
||||
/datum/component/shrapnel/Initialize(projectile_type, radius=1, override_projectile_range)
|
||||
if(!isgun(parent) && !ismachinery(parent) && !isstructure(parent))
|
||||
/datum/component/mirv/Initialize(projectile_type, radius=1, override_projectile_range)
|
||||
if(!isgun(parent) && !ismachinery(parent) && !isstructure(parent) && !isgrenade(parent))
|
||||
return COMPONENT_INCOMPATIBLE
|
||||
|
||||
src.projectile_type = projectile_type
|
||||
src.radius = radius
|
||||
src.override_projectile_range = override_projectile_range
|
||||
if(isgrenade(parent))
|
||||
parent.AddComponent(/datum/component/pellet_cloud, projectile_type=projectile_type)
|
||||
|
||||
/datum/component/shrapnel/RegisterWithParent()
|
||||
/datum/component/mirv/RegisterWithParent()
|
||||
. = ..()
|
||||
if(ismachinery(parent) || isstructure(parent) || isgun(parent)) // turrets, etc
|
||||
RegisterSignal(parent, COMSIG_PROJECTILE_ON_HIT, .proc/projectile_hit)
|
||||
|
||||
/datum/component/shrapnel/UnregisterFromParent()
|
||||
/datum/component/mirv/UnregisterFromParent()
|
||||
. = ..()
|
||||
UnregisterSignal(parent, list(COMSIG_PROJECTILE_ON_HIT))
|
||||
|
||||
/datum/component/shrapnel/proc/projectile_hit(atom/fired_from, atom/movable/firer, atom/target, Angle)
|
||||
/datum/component/mirv/proc/projectile_hit(atom/fired_from, atom/movable/firer, atom/target, Angle)
|
||||
do_shrapnel(firer, target)
|
||||
|
||||
/datum/component/shrapnel/proc/do_shrapnel(mob/firer, atom/target)
|
||||
/datum/component/mirv/proc/do_shrapnel(mob/firer, atom/target)
|
||||
if(radius < 1)
|
||||
return
|
||||
var/turf/target_turf = get_turf(target)
|
||||
for(var/turf/shootat_turf in RANGE_TURFS(radius, target) - RANGE_TURFS(radius-1, target))
|
||||
var/obj/item/projectile/P = new projectile_type(target_turf)
|
||||
|
||||
var/obj/item/projectile/P = new projectile_type(target_turf)
|
||||
//Shooting Code:
|
||||
P.range = radius+1
|
||||
if(override_projectile_range)
|
||||
@@ -0,0 +1,74 @@
|
||||
/**
|
||||
* omen.dm: For when you want someone to have a really bad day
|
||||
*
|
||||
* When you attach an omen component to someone, they start running the risk of all sorts of bad environmental injuries, like nearby vending machines randomly falling on you,
|
||||
* or hitting your head really hard when you slip and fall, or... well, for now those two are all I have. More will come.
|
||||
*
|
||||
* Omens are removed once the victim is either maimed by one of the possible injuries, or if they receive a blessing (read: bashing with a bible) from the chaplain.
|
||||
*/
|
||||
/datum/component/omen
|
||||
dupe_mode = COMPONENT_DUPE_UNIQUE
|
||||
|
||||
/// Whatever's causing the omen, if there is one. Destroying the vessel won't stop the omen, but we destroy the vessel (if one exists) upon the omen ending
|
||||
var/obj/vessel
|
||||
|
||||
/datum/component/omen/Initialize(silent=FALSE, vessel)
|
||||
if(!isliving(parent))
|
||||
return COMPONENT_INCOMPATIBLE
|
||||
var/mob/person = parent
|
||||
if(!silent)
|
||||
to_chat(person, "<span class='warning'>You get a bad feeling...</span>")
|
||||
src.vessel = vessel
|
||||
|
||||
/datum/component/omen/Destroy(force, silent)
|
||||
if(vessel)
|
||||
vessel.visible_message("<span class='warning'>[vessel] burns up in a sinister flash, taking an evil energy with it...</span>")
|
||||
vessel = null
|
||||
return ..()
|
||||
|
||||
/datum/component/omen/RegisterWithParent()
|
||||
RegisterSignal(parent, COMSIG_MOVABLE_MOVED, .proc/check_accident)
|
||||
RegisterSignal(parent, COMSIG_LIVING_STATUS_KNOCKDOWN, .proc/check_slip)
|
||||
RegisterSignal(parent, COMSIG_ADD_MOOD_EVENT, .proc/check_bless)
|
||||
|
||||
/datum/component/omen/UnregisterFromParent()
|
||||
UnregisterSignal(parent, list(COMSIG_LIVING_STATUS_KNOCKDOWN, COMSIG_MOVABLE_MOVED, COMSIG_ADD_MOOD_EVENT))
|
||||
|
||||
/**
|
||||
* check_accident() is called each step we take
|
||||
*
|
||||
* While we're walking around, roll to see if there's any environmental hazards (currently only vending machines) on one of the adjacent tiles we can trigger.
|
||||
* We do the prob() at the beginning to A. add some tension for /when/ it will strike, and B. (more importantly) ameliorate the fact that we're checking up to 5 turfs's contents each time
|
||||
*/
|
||||
/datum/component/omen/proc/check_accident(atom/movable/our_guy)
|
||||
if(!prob(15))
|
||||
return
|
||||
for(var/t in get_adjacent_open_turfs(our_guy))
|
||||
var/turf/the_turf = t
|
||||
for(var/obj/machinery/vending/darth_vendor in the_turf)
|
||||
if(darth_vendor.tiltable)
|
||||
darth_vendor.tilt(our_guy)
|
||||
qdel(src)
|
||||
return
|
||||
|
||||
/// If we get knocked down, see if we have a really bad slip and bash our head hard
|
||||
/datum/component/omen/proc/check_slip(mob/living/our_guy, amount)
|
||||
if(amount <= 0 || prob(50)) // 50% chance to bonk our head
|
||||
return
|
||||
|
||||
var/obj/item/bodypart/the_head = our_guy.get_bodypart(BODY_ZONE_HEAD)
|
||||
if(!the_head)
|
||||
return
|
||||
|
||||
playsound(get_turf(our_guy), "sound/effects/tableheadsmash.ogg", 90, TRUE)
|
||||
our_guy.visible_message("<span class='danger'>[our_guy] hits [our_guy.p_their()] head really badly falling down!</span>", "<span class='userdanger'>You hit your head really badly falling down!</span>")
|
||||
the_head.receive_damage(75)
|
||||
our_guy.adjustOrganLoss(ORGAN_SLOT_BRAIN, 100)
|
||||
qdel(src)
|
||||
|
||||
/// Hijack the mood system to see if we get the blessing mood event to cancel the omen
|
||||
/datum/component/omen/proc/check_bless(mob/living/our_guy, category)
|
||||
if(category != "blessing")
|
||||
return
|
||||
to_chat(our_guy, "<span class='nicegreen'>You feel a horrible omen lifted off your shoulders!</span>")
|
||||
qdel(src)
|
||||
@@ -0,0 +1,283 @@
|
||||
/*
|
||||
* This component is used when you want to create a bunch of shrapnel or projectiles (say, shrapnel from a fragmentation grenade, or buckshot from a shotgun) from a central point,
|
||||
* without necessarily printing a separate message for every single impact. This component should be instantiated right when you need it (like the moment of firing), then activated
|
||||
* by signal.
|
||||
*
|
||||
* Pellet cloud currently works on two classes of sources: directed (ammo casings), and circular (grenades, landmines).
|
||||
* -Directed: This means you're shooting multiple pellets, like buckshot. If an ammo casing is defined as having multiple pellets, it will automatically create a pellet cloud
|
||||
* and call COMSIG_PELLET_CLOUD_INIT (see [/obj/item/ammo_casing/proc/fire_casing]). Thus, the only projectiles fired will be the ones fired here.
|
||||
* The magnitude var controls how many pellets are created.
|
||||
* -Circular: This results in a big spray of shrapnel flying all around the detonation point when the grenade fires COMSIG_GRENADE_PRIME or landmine triggers COMSIG_MINE_TRIGGERED.
|
||||
* The magnitude var controls how big the detonation radius is (the bigger the magnitude, the more shrapnel is created). Grenades can be covered with bodies to reduce shrapnel output.
|
||||
*
|
||||
* Once all of the fired projectiles either hit a target or disappear due to ranging out/whatever else, we resolve the list of all the things we hit and print aggregate messages so we get
|
||||
* one "You're hit by 6 buckshot pellets" vs 6x "You're hit by the buckshot blah blah" messages.
|
||||
*
|
||||
* Note that this is how all guns handle shooting ammo casings with multiple pellets, in case such a thing comes up.
|
||||
*/
|
||||
|
||||
/datum/component/pellet_cloud
|
||||
/// What's the projectile path of the shrapnel we're shooting?
|
||||
var/projectile_type
|
||||
|
||||
/// How many shrapnel projectiles are we responsible for tracking? May be reduced for grenades if someone dives on top of it. Defined by ammo casing for casings, derived from magnitude otherwise
|
||||
var/num_pellets
|
||||
/// For grenades/landmines, how big is the radius of turfs we're targeting? Note this does not effect the projectiles range, only how many we generate
|
||||
var/radius = 4
|
||||
|
||||
/// The list of pellets we're responsible for tracking, once these are all accounted for, we finalize.
|
||||
var/list/pellets = list()
|
||||
/// An associated list with the atom hit as the key and how many pellets they've eaten for the value, for printing aggregate messages
|
||||
var/list/targets_hit = list()
|
||||
/// For grenades, any /mob/living's the grenade is moved onto, see [/datum/component/pellet_cloud/proc/handle_martyrs()]
|
||||
var/list/bodies
|
||||
/// For grenades, tracking people who die covering a grenade for achievement purposes, see [/datum/component/pellet_cloud/proc/handle_martyrs()]
|
||||
var/list/purple_hearts
|
||||
|
||||
/// For grenades, tracking how many pellets are removed due to martyrs and how many pellets are added due to the last person to touch it being on top of it
|
||||
var/pellet_delta = 0
|
||||
/// how many pellets ranged out without hitting anything
|
||||
var/terminated
|
||||
/// how many pellets impacted something
|
||||
var/hits
|
||||
/// If the parent tried deleting and we're not done yet, we send it to nullspace then delete it after
|
||||
var/queued_delete = FALSE
|
||||
|
||||
/// for if we're an ammo casing being fired
|
||||
var/mob/living/shooter
|
||||
|
||||
/datum/component/pellet_cloud/Initialize(projectile_type=/obj/item/shrapnel, magnitude=5)
|
||||
if(!isammocasing(parent) && !isgrenade(parent) && !islandmine(parent))
|
||||
return COMPONENT_INCOMPATIBLE
|
||||
|
||||
if(magnitude < 1)
|
||||
stack_trace("Invalid magnitude [magnitude] < 1 on pellet_cloud, parent: [parent]")
|
||||
magnitude = 1
|
||||
|
||||
src.projectile_type = projectile_type
|
||||
|
||||
if(isammocasing(parent))
|
||||
num_pellets = magnitude
|
||||
else if(isgrenade(parent) || islandmine(parent))
|
||||
radius = magnitude
|
||||
|
||||
/datum/component/pellet_cloud/Destroy(force, silent)
|
||||
purple_hearts = null
|
||||
pellets = null
|
||||
targets_hit = null
|
||||
bodies = null
|
||||
return ..()
|
||||
|
||||
/datum/component/pellet_cloud/RegisterWithParent()
|
||||
RegisterSignal(parent, COMSIG_PARENT_PREQDELETED, .proc/nullspace_parent)
|
||||
if(isammocasing(parent))
|
||||
RegisterSignal(parent, COMSIG_PELLET_CLOUD_INIT, .proc/create_casing_pellets)
|
||||
else if(isgrenade(parent))
|
||||
RegisterSignal(parent, COMSIG_GRENADE_ARMED, .proc/grenade_armed)
|
||||
RegisterSignal(parent, COMSIG_GRENADE_PRIME, .proc/create_blast_pellets)
|
||||
else if(islandmine(parent))
|
||||
RegisterSignal(parent, COMSIG_MINE_TRIGGERED, .proc/create_blast_pellets)
|
||||
|
||||
/datum/component/pellet_cloud/UnregisterFromParent()
|
||||
UnregisterSignal(parent, list(COMSIG_PARENT_PREQDELETED, COMSIG_PELLET_CLOUD_INIT, COMSIG_GRENADE_PRIME, COMSIG_GRENADE_ARMED, COMSIG_MOVABLE_MOVED, COMSIG_MOVABLE_UNCROSSED, COMSIG_MINE_TRIGGERED, COMSIG_ITEM_DROPPED))
|
||||
|
||||
/**
|
||||
* create_casing_pellets() is for directed pellet clouds for ammo casings that have multiple pellets (buckshot and scatter lasers for instance)
|
||||
*
|
||||
* Honestly this is mostly just a rehash of [/obj/item/ammo_casing/proc/fire_casing()] for pellet counts > 1, except this lets us tamper with the pellets and hook onto them for tracking purposes.
|
||||
* The arguments really don't matter, this proc is triggered by COMSIG_PELLET_CLOUD_INIT which is only for this really, it's just a big mess of the state vars we need for doing the stuff over here.
|
||||
*/
|
||||
/datum/component/pellet_cloud/proc/create_casing_pellets(obj/item/ammo_casing/shell, atom/target, mob/living/user, fired_from, randomspread, spread, zone_override, params, distro)
|
||||
shooter = user
|
||||
var/targloc = get_turf(target)
|
||||
if(!zone_override)
|
||||
zone_override = shooter.zone_selected
|
||||
|
||||
for(var/i in 1 to num_pellets)
|
||||
shell.ready_proj(target, user, SUPPRESSED_VERY, zone_override, fired_from)
|
||||
if(distro)
|
||||
if(randomspread)
|
||||
spread = round((rand() - 0.5) * distro)
|
||||
else //Smart spread
|
||||
spread = round((i / num_pellets - 0.5) * distro)
|
||||
|
||||
RegisterSignal(shell.BB, COMSIG_PROJECTILE_SELF_ON_HIT, .proc/pellet_hit)
|
||||
RegisterSignal(shell.BB, list(COMSIG_PROJECTILE_RANGE_OUT, COMSIG_PARENT_QDELETING), .proc/pellet_range)
|
||||
pellets += shell.BB
|
||||
if(!shell.throw_proj(target, targloc, shooter, params, spread))
|
||||
return
|
||||
if(i != num_pellets)
|
||||
shell.newshot()
|
||||
|
||||
/**
|
||||
* create_blast_pellets() is for when we have a central point we want to shred the surroundings of with a ring of shrapnel, namely frag grenades and landmines.
|
||||
*
|
||||
* Note that grenades have extra handling for someone throwing themselves/being thrown on top of it, while landmines do not (obviously, it's a landmine!). See [/datum/component/pellet_cloud/proc/handle_martyrs()]
|
||||
*/
|
||||
/datum/component/pellet_cloud/proc/create_blast_pellets(obj/O, mob/living/lanced_by)
|
||||
var/atom/A = parent
|
||||
|
||||
if(isgrenade(parent)) // handle_martyrs can reduce the radius and thus the number of pellets we produce if someone dives on top of a frag grenade
|
||||
handle_martyrs(lanced_by) // note that we can modify radius in this proc
|
||||
|
||||
if(radius < 1)
|
||||
return
|
||||
|
||||
var/list/all_the_turfs_were_gonna_lacerate = RANGE_TURFS(radius, A) - RANGE_TURFS(radius-1, A)
|
||||
num_pellets = all_the_turfs_were_gonna_lacerate.len + pellet_delta
|
||||
|
||||
for(var/T in all_the_turfs_were_gonna_lacerate)
|
||||
var/turf/shootat_turf = T
|
||||
pew(shootat_turf)
|
||||
|
||||
/**
|
||||
* handle_martyrs() is used for grenades that shoot shrapnel to check if anyone threw themselves/were thrown on top of the grenade, thus absorbing a good chunk of the shrapnel
|
||||
*
|
||||
* Between the time the grenade is armed and the actual detonation, we set var/list/bodies to the list of mobs currently on the new tile, as if the grenade landed on top of them, tracking if any of them move off the tile and removing them from the "under" list
|
||||
* Once the grenade detonates, handle_martyrs() is called and gets all the new mobs on the tile, and add the ones not in var/list/bodies to var/list/martyrs
|
||||
* We then iterate through the martyrs and reduce the shrapnel magnitude for each mob on top of it, shredding each of them with some of the shrapnel they helped absorb. This can snuff out all of the shrapnel if there's enough bodies
|
||||
*
|
||||
* Note we track anyone who's alive and client'd when they get shredded in var/list/purple_hearts, for achievement checking later
|
||||
*/
|
||||
/datum/component/pellet_cloud/proc/handle_martyrs(mob/living/lanced_by)
|
||||
var/magnitude_absorbed
|
||||
var/list/martyrs = list()
|
||||
|
||||
var/self_harm_radius_mult = 3
|
||||
|
||||
if(lanced_by && prob(60))
|
||||
to_chat(lanced_by, "<span class='userdanger'>Your plan to whack someone with a grenade on a stick backfires on you, literally!</span>")
|
||||
self_harm_radius_mult = 1 // we'll still give the guy who got hit some extra shredding, but not 3*radius
|
||||
pellet_delta += radius
|
||||
for(var/i in 1 to radius)
|
||||
pew(lanced_by) // thought you could be tricky and lance someone with no ill effects!!
|
||||
|
||||
for(var/mob/living/body in get_turf(parent))
|
||||
if(body == shooter)
|
||||
pellet_delta += radius * self_harm_radius_mult
|
||||
for(var/i in 1 to radius * self_harm_radius_mult)
|
||||
pew(body) // free shrapnel if it goes off in your hand, and it doesn't even count towards the absorbed. fun!
|
||||
else if(!(body in bodies))
|
||||
martyrs += body // promoted from a corpse to a hero
|
||||
|
||||
for(var/M in martyrs)
|
||||
var/mob/living/martyr = M
|
||||
if(radius > 4)
|
||||
martyr.visible_message("<b><span class='danger'>[martyr] heroically covers \the [parent] with [martyr.p_their()] body, absorbing a load of the shrapnel!</span></b>", "<span class='userdanger'>You heroically cover \the [parent] with your body, absorbing a load of the shrapnel!</span>")
|
||||
magnitude_absorbed += round(radius * 0.5)
|
||||
else if(radius >= 2)
|
||||
martyr.visible_message("<b><span class='danger'>[martyr] heroically covers \the [parent] with [martyr.p_their()] body, absorbing some of the shrapnel!</span></b>", "<span class='userdanger'>You heroically cover \the [parent] with your body, absorbing some of the shrapnel!</span>")
|
||||
magnitude_absorbed += 2
|
||||
else
|
||||
martyr.visible_message("<b><span class='danger'>[martyr] heroically covers \the [parent] with [martyr.p_their()] body, snuffing out the shrapnel!</span></b>", "<span class='userdanger'>You heroically cover \the [parent] with your body, snuffing out the shrapnel!</span>")
|
||||
magnitude_absorbed = radius
|
||||
|
||||
var/pellets_absorbed = (radius ** 2) - ((radius - magnitude_absorbed - 1) ** 2)
|
||||
radius -= magnitude_absorbed
|
||||
pellet_delta -= round(pellets_absorbed * 0.5)
|
||||
|
||||
if(martyr.stat != DEAD && martyr.client)
|
||||
LAZYADD(purple_hearts, martyr)
|
||||
RegisterSignal(martyr, COMSIG_PARENT_QDELETING, .proc/on_target_qdel, override=TRUE)
|
||||
|
||||
for(var/i in 1 to round(pellets_absorbed * 0.5))
|
||||
pew(martyr)
|
||||
|
||||
if(radius < 1)
|
||||
break
|
||||
|
||||
///One of our pellets hit something, record what it was and check if we're done (terminated == num_pellets)
|
||||
/datum/component/pellet_cloud/proc/pellet_hit(obj/item/projectile/P, atom/movable/firer, atom/target, Angle)
|
||||
pellets -= P
|
||||
terminated++
|
||||
hits++
|
||||
targets_hit[target]++
|
||||
if(targets_hit[target] == 1)
|
||||
RegisterSignal(target, COMSIG_PARENT_QDELETING, .proc/on_target_qdel, override=TRUE)
|
||||
UnregisterSignal(P, list(COMSIG_PARENT_QDELETING, COMSIG_PROJECTILE_RANGE_OUT, COMSIG_PROJECTILE_SELF_ON_HIT))
|
||||
if(terminated == num_pellets)
|
||||
finalize()
|
||||
|
||||
///One of our pellets disappeared due to hitting their max range (or just somehow got qdel'd), remove it from our list and check if we're done (terminated == num_pellets)
|
||||
/datum/component/pellet_cloud/proc/pellet_range(obj/item/projectile/P)
|
||||
pellets -= P
|
||||
terminated++
|
||||
UnregisterSignal(P, list(COMSIG_PARENT_QDELETING, COMSIG_PROJECTILE_RANGE_OUT, COMSIG_PROJECTILE_SELF_ON_HIT))
|
||||
if(terminated == num_pellets)
|
||||
finalize()
|
||||
|
||||
/// Minor convenience function for creating each shrapnel piece with circle explosions, mostly stolen from the MIRV component
|
||||
/datum/component/pellet_cloud/proc/pew(atom/target, spread=0)
|
||||
var/obj/item/projectile/P = new projectile_type(get_turf(parent))
|
||||
|
||||
//Shooting Code:
|
||||
P.spread = spread
|
||||
P.original = target
|
||||
P.fired_from = parent
|
||||
P.firer = parent // don't hit ourself that would be really annoying
|
||||
P.permutated += parent // don't hit the target we hit already with the flak
|
||||
P.suppressed = SUPPRESSED_VERY // set the projectiles to make no message so we can do our own aggregate message
|
||||
P.preparePixelProjectile(target, parent)
|
||||
RegisterSignal(P, COMSIG_PROJECTILE_SELF_ON_HIT, .proc/pellet_hit)
|
||||
RegisterSignal(P, list(COMSIG_PROJECTILE_RANGE_OUT, COMSIG_PARENT_QDELETING), .proc/pellet_range)
|
||||
pellets += P
|
||||
P.fire()
|
||||
|
||||
///All of our pellets are accounted for, time to go target by target and tell them how many things they got hit by.
|
||||
/datum/component/pellet_cloud/proc/finalize()
|
||||
var/obj/item/projectile/P = projectile_type
|
||||
var/proj_name = initial(P.name)
|
||||
|
||||
for(var/atom/target in targets_hit)
|
||||
var/num_hits = targets_hit[target]
|
||||
UnregisterSignal(target, COMSIG_PARENT_QDELETING)
|
||||
if(num_hits > 1)
|
||||
target.visible_message("<span class='danger'>[target] is hit by [num_hits] [proj_name]s!</span>", null, null, COMBAT_MESSAGE_RANGE, target)
|
||||
to_chat(target, "<span class='userdanger'>You're hit by [num_hits] [proj_name]s!</span>")
|
||||
else
|
||||
target.visible_message("<span class='danger'>[target] is hit by a [proj_name]!</span>", null, null, COMBAT_MESSAGE_RANGE, target)
|
||||
to_chat(target, "<span class='userdanger'>You're hit by a [proj_name]!</span>")
|
||||
|
||||
UnregisterSignal(parent, COMSIG_PARENT_PREQDELETED)
|
||||
if(queued_delete)
|
||||
qdel(parent)
|
||||
qdel(src)
|
||||
|
||||
/// Look alive, we're armed! Now we start watching to see if anyone's covering us
|
||||
/datum/component/pellet_cloud/proc/grenade_armed(obj/item/nade)
|
||||
if(ismob(nade.loc))
|
||||
shooter = nade.loc
|
||||
LAZYINITLIST(bodies)
|
||||
RegisterSignal(parent, COMSIG_ITEM_DROPPED, .proc/grenade_dropped)
|
||||
RegisterSignal(parent, COMSIG_MOVABLE_MOVED, .proc/grenade_moved)
|
||||
RegisterSignal(parent, COMSIG_MOVABLE_UNCROSSED, .proc/grenade_uncrossed)
|
||||
|
||||
/// Someone dropped the grenade, so set them to the shooter in case they're on top of it when it goes off
|
||||
/datum/component/pellet_cloud/proc/grenade_dropped(obj/item/nade, mob/living/slick_willy)
|
||||
shooter = slick_willy
|
||||
grenade_moved()
|
||||
|
||||
/// Our grenade has moved, reset var/list/bodies so we're "on top" of any mobs currently on the tile
|
||||
/datum/component/pellet_cloud/proc/grenade_moved()
|
||||
LAZYCLEARLIST(bodies)
|
||||
for(var/mob/living/L in get_turf(parent))
|
||||
RegisterSignal(L, COMSIG_PARENT_QDELETING, .proc/on_target_qdel, override=TRUE)
|
||||
bodies += L
|
||||
|
||||
/// Someone who was originally "under" the grenade has moved off the tile and is now eligible for being a martyr and "covering" it
|
||||
/datum/component/pellet_cloud/proc/grenade_uncrossed(datum/source, atom/movable/AM)
|
||||
bodies -= AM
|
||||
|
||||
/// Our grenade or landmine or caseless shell or whatever tried deleting itself, so we intervene and nullspace it until we're done here
|
||||
/datum/component/pellet_cloud/proc/nullspace_parent()
|
||||
var/atom/movable/AM = parent
|
||||
AM.moveToNullspace()
|
||||
queued_delete = TRUE
|
||||
return TRUE
|
||||
|
||||
/// Someone who was originally "under" the grenade has moved off the tile and is now eligible for being a martyr and "covering" it
|
||||
/datum/component/pellet_cloud/proc/on_target_qdel(atom/target)
|
||||
UnregisterSignal(target, COMSIG_PARENT_QDELETING)
|
||||
targets_hit -= target
|
||||
bodies -= target
|
||||
purple_hearts -= target
|
||||
@@ -69,8 +69,9 @@
|
||||
out += "[out ? " and it " : "[master] "]seems to be glowing a bit."
|
||||
if(RAD_AMOUNT_HIGH to INFINITY) //At this level the object can contaminate other objects
|
||||
out += "[out ? " and it " : "[master] "]hurts to look at."
|
||||
else
|
||||
out += "."
|
||||
if(!LAZYLEN(out))
|
||||
return
|
||||
out += "."
|
||||
examine_list += out.Join()
|
||||
|
||||
/datum/component/radioactive/proc/rad_attack(datum/source, atom/movable/target, mob/living/user)
|
||||
|
||||
@@ -8,6 +8,8 @@
|
||||
var/list/faction = list("mining")
|
||||
|
||||
/datum/component/spawner/Initialize(_mob_types, _spawn_time, _faction, _spawn_text, _max_mobs)
|
||||
if(!isatom(parent))
|
||||
return COMPONENT_INCOMPATIBLE
|
||||
if(_spawn_time)
|
||||
spawn_time=_spawn_time
|
||||
if(_mob_types)
|
||||
@@ -19,20 +21,25 @@
|
||||
if(_max_mobs)
|
||||
max_mobs=_max_mobs
|
||||
|
||||
RegisterSignal(parent, list(COMSIG_PARENT_QDELETING), .proc/stop_spawning)
|
||||
RegisterSignal(parent, COMSIG_PARENT_QDELETING, .proc/stop_spawning)
|
||||
RegisterSignal(parent, COMSIG_OBJ_ATTACK_GENERIC, .proc/on_attack_generic)
|
||||
START_PROCESSING(SSprocessing, src)
|
||||
|
||||
/datum/component/spawner/process()
|
||||
try_spawn_mob()
|
||||
|
||||
|
||||
/datum/component/spawner/proc/stop_spawning(force, hint)
|
||||
/datum/component/spawner/proc/stop_spawning(datum/source, force, hint)
|
||||
STOP_PROCESSING(SSprocessing, src)
|
||||
for(var/mob/living/simple_animal/L in spawned_mobs)
|
||||
if(L.nest == src)
|
||||
L.nest = null
|
||||
spawned_mobs = null
|
||||
|
||||
// Stopping clientless simple mobs' from indiscriminately bashing their own spawners due DestroySurroundings() et similars.
|
||||
/datum/component/spawner/proc/on_attack_generic(datum/source, mob/user, damage_amount, damage_type, damage_flag, sound_effect, armor_penetration)
|
||||
if(!user.client && ((user.faction & faction) || (user in spawned_mobs)))
|
||||
return COMPONENT_STOP_GENERIC_ATTACK
|
||||
|
||||
/datum/component/spawner/proc/try_spawn_mob()
|
||||
var/atom/P = parent
|
||||
if(spawned_mobs.len >= max_mobs)
|
||||
|
||||
@@ -206,7 +206,7 @@
|
||||
user.set_resting(FALSE, TRUE, FALSE)
|
||||
user.forceMove(get_turf(target))
|
||||
target.adjustStaminaLoss(65)
|
||||
target.Paralyze(10)
|
||||
target.Paralyze(10)
|
||||
target.DefaultCombatKnockdown(20)
|
||||
if(ishuman(target) && iscarbon(user))
|
||||
target.grabbedby(user)
|
||||
@@ -354,7 +354,7 @@
|
||||
playsound(user, 'sound/effects/blobattack.ogg', 60, TRUE)
|
||||
playsound(user, 'sound/effects/splat.ogg', 70, TRUE)
|
||||
user.emote("scream")
|
||||
user.gain_trauma(/datum/brain_trauma/severe/paralysis/paraplegic) // oopsie indeed!
|
||||
user.gain_trauma(/datum/brain_trauma/severe/paralysis/spinesnapped) // oopsie indeed!
|
||||
shake_camera(user, 7, 7)
|
||||
user.overlay_fullscreen("flash", /obj/screen/fullscreen/flash)
|
||||
user.clear_fullscreen("flash", 4.5)
|
||||
@@ -415,10 +415,10 @@
|
||||
for(var/i = 0, i < speed, i++)
|
||||
var/obj/item/shard/shard = new /obj/item/shard(get_turf(user))
|
||||
//shard.embedding = list(embed_chance = 100, ignore_throwspeed_threshold = TRUE, impact_pain_mult=3, pain_chance=5)
|
||||
//shard.AddElement(/datum/element/embed, shard.embedding)
|
||||
shard.updateEmbedding()
|
||||
user.hitby(shard, skipcatch = TRUE, hitpush = FALSE)
|
||||
//shard.embedding = list()
|
||||
//shard.AddElement(/datum/element/embed, shard.embedding)
|
||||
shard.embedding = list()
|
||||
shard.updateEmbedding()
|
||||
W.obj_destruction()
|
||||
user.adjustStaminaLoss(10 * speed)
|
||||
user.DefaultCombatKnockdown(40)
|
||||
|
||||
@@ -20,11 +20,11 @@
|
||||
|
||||
/datum/disease/transformation/Copy()
|
||||
var/datum/disease/transformation/D = ..()
|
||||
D.stage1 = stage1.Copy()
|
||||
D.stage2 = stage2.Copy()
|
||||
D.stage3 = stage3.Copy()
|
||||
D.stage4 = stage4.Copy()
|
||||
D.stage5 = stage5.Copy()
|
||||
D.stage1 = stage1?.Copy()
|
||||
D.stage2 = stage2?.Copy()
|
||||
D.stage3 = stage3?.Copy()
|
||||
D.stage4 = stage4?.Copy()
|
||||
D.stage5 = stage5?.Copy()
|
||||
D.new_form = D.new_form
|
||||
return D
|
||||
|
||||
@@ -52,9 +52,9 @@
|
||||
to_chat(affected_mob, pick(stage5))
|
||||
if(QDELETED(affected_mob))
|
||||
return
|
||||
if(affected_mob.notransform)
|
||||
if(affected_mob.mob_transforming)
|
||||
return
|
||||
affected_mob.notransform = 1
|
||||
affected_mob.mob_transforming = 1
|
||||
for(var/obj/item/W in affected_mob.get_equipped_items(TRUE))
|
||||
affected_mob.dropItemToGround(W)
|
||||
for(var/obj/item/I in affected_mob.held_items)
|
||||
|
||||
@@ -19,11 +19,13 @@
|
||||
SHOULD_CALL_PARENT(1)
|
||||
if(type == /datum/element)
|
||||
return ELEMENT_INCOMPATIBLE
|
||||
SEND_SIGNAL(target, COMSIG_ELEMENT_ATTACH, src)
|
||||
if(element_flags & ELEMENT_DETACH)
|
||||
RegisterSignal(target, COMSIG_PARENT_QDELETING, .proc/Detach, override = TRUE)
|
||||
|
||||
/// Deactivates the functionality defines by the element on the given datum
|
||||
/datum/element/proc/Detach(datum/source, force)
|
||||
SEND_SIGNAL(source, COMSIG_ELEMENT_DETACH, src)
|
||||
SHOULD_CALL_PARENT(1)
|
||||
UnregisterSignal(source, COMSIG_PARENT_QDELETING)
|
||||
|
||||
|
||||
@@ -8,8 +8,11 @@
|
||||
if(. == ELEMENT_INCOMPATIBLE || !isatom(target) || isarea(target))
|
||||
return ELEMENT_INCOMPATIBLE
|
||||
beauty = beautyamount
|
||||
RegisterSignal(target, COMSIG_ENTER_AREA, .proc/enter_area)
|
||||
RegisterSignal(target, COMSIG_EXIT_AREA, .proc/exit_area)
|
||||
|
||||
if(ismovable(target))
|
||||
RegisterSignal(target, COMSIG_ENTER_AREA, .proc/enter_area)
|
||||
RegisterSignal(target, COMSIG_EXIT_AREA, .proc/exit_area)
|
||||
|
||||
var/area/A = get_area(target)
|
||||
if(A)
|
||||
enter_area(null, A)
|
||||
|
||||
@@ -0,0 +1,227 @@
|
||||
/*
|
||||
The presence of this element allows an item (or a projectile carrying an item) to embed itself in a human or turf when it is thrown into a target (whether by hand, gun, or explosive wave) with either
|
||||
at least 4 throwspeed (EMBED_THROWSPEED_THRESHOLD) or ignore_throwspeed_threshold set to TRUE. Items meant to be used as shrapnel for projectiles should have ignore_throwspeed_threshold set to true.
|
||||
|
||||
Whether we're dealing with a direct /obj/item (throwing a knife at someone) or an /obj/projectile with a shrapnel_type, how we handle things plays out the same, with one extra step separating them.
|
||||
Items simply make their COMSIG_MOVABLE_IMPACT or COMSIG_MOVABLE_IMPACT_ZONE check (against a closed turf or a carbon, respectively), while projectiles check on COMSIG_PROJECTILE_SELF_ON_HIT.
|
||||
Upon a projectile hitting a valid target, it spawns whatever type of payload it has defined, then has that try to embed itself in the target on its own.
|
||||
|
||||
Otherwise non-embeddable or stickable items can be made embeddable/stickable through wizard events/sticky tape/admin memes.
|
||||
*/
|
||||
|
||||
#define STANDARD_WALL_HARDNESS 40
|
||||
|
||||
/datum/element/embed
|
||||
element_flags = ELEMENT_BESPOKE
|
||||
id_arg_index = 2
|
||||
var/initialized = FALSE /// whether we can skip assigning all the vars (since these are bespoke elements, we don't have to reset the vars every time we attach to something, we already know what we are!)
|
||||
|
||||
// all of this stuff is explained in _DEFINES/combat.dm
|
||||
var/embed_chance
|
||||
var/fall_chance
|
||||
var/pain_chance
|
||||
var/pain_mult
|
||||
var/remove_pain_mult
|
||||
var/impact_pain_mult
|
||||
var/rip_time
|
||||
var/ignore_throwspeed_threshold
|
||||
var/jostle_chance
|
||||
var/jostle_pain_mult
|
||||
var/pain_stam_pct
|
||||
var/payload_type
|
||||
var/embed_chance_turf_mod
|
||||
|
||||
/datum/element/embed/Attach(datum/target, embed_chance, fall_chance, pain_chance, pain_mult, remove_pain_mult, impact_pain_mult, rip_time, ignore_throwspeed_threshold, jostle_chance, jostle_pain_mult, pain_stam_pct, embed_chance_turf_mod, projectile_payload=/obj/item/shard)
|
||||
. = ..()
|
||||
|
||||
if(!isitem(target) && !isprojectile(target))
|
||||
return ELEMENT_INCOMPATIBLE
|
||||
|
||||
if(isitem(target))
|
||||
RegisterSignal(target, COMSIG_MOVABLE_IMPACT_ZONE, .proc/checkEmbedMob)
|
||||
RegisterSignal(target, COMSIG_MOVABLE_IMPACT, .proc/checkEmbedOther)
|
||||
RegisterSignal(target, COMSIG_ELEMENT_ATTACH, .proc/severancePackage)
|
||||
RegisterSignal(target, COMSIG_PARENT_EXAMINE, .proc/examined)
|
||||
RegisterSignal(target, COMSIG_EMBED_TRY_FORCE, .proc/tryForceEmbed)
|
||||
RegisterSignal(target, COMSIG_ITEM_DISABLE_EMBED, .proc/detachFromWeapon)
|
||||
if(!initialized)
|
||||
src.embed_chance = embed_chance
|
||||
src.fall_chance = fall_chance
|
||||
src.pain_chance = pain_chance
|
||||
src.pain_mult = pain_mult
|
||||
src.remove_pain_mult = remove_pain_mult
|
||||
src.rip_time = rip_time
|
||||
src.impact_pain_mult = impact_pain_mult
|
||||
src.ignore_throwspeed_threshold = ignore_throwspeed_threshold
|
||||
src.jostle_chance = jostle_chance
|
||||
src.jostle_pain_mult = jostle_pain_mult
|
||||
src.pain_stam_pct = pain_stam_pct
|
||||
src.embed_chance_turf_mod = embed_chance_turf_mod
|
||||
initialized = TRUE
|
||||
else
|
||||
payload_type = projectile_payload
|
||||
RegisterSignal(target, COMSIG_PROJECTILE_SELF_ON_HIT, .proc/checkEmbedProjectile)
|
||||
|
||||
|
||||
/datum/element/embed/Detach(obj/target)
|
||||
. = ..()
|
||||
if(isitem(target))
|
||||
UnregisterSignal(target, list(COMSIG_MOVABLE_IMPACT_ZONE, COMSIG_ELEMENT_ATTACH, COMSIG_MOVABLE_IMPACT, COMSIG_PARENT_EXAMINE, COMSIG_EMBED_TRY_FORCE, COMSIG_ITEM_DISABLE_EMBED))
|
||||
else
|
||||
UnregisterSignal(target, list(COMSIG_PROJECTILE_SELF_ON_HIT))
|
||||
|
||||
|
||||
/// Checking to see if we're gonna embed into a human
|
||||
/datum/element/embed/proc/checkEmbedMob(obj/item/weapon, mob/living/carbon/victim, hit_zone, datum/thrownthing/throwingdatum, blocked = FALSE, forced = FALSE)
|
||||
if(blocked || !istype(victim) || HAS_TRAIT(victim, TRAIT_PIERCEIMMUNE))
|
||||
return
|
||||
|
||||
var/actual_chance = embed_chance
|
||||
|
||||
if(!weapon.isEmbedHarmless()) // all the armor in the world won't save you from a kick me sign
|
||||
var/armor = max(victim.run_armor_check(hit_zone, "bullet", silent=TRUE), victim.run_armor_check(hit_zone, "bomb", silent=TRUE)) // we'll be nice and take the better of bullet and bomb armor
|
||||
|
||||
if(armor) // we only care about armor penetration if there's actually armor to penetrate
|
||||
var/pen_mod = -armor + weapon.armour_penetration // even a little bit of armor can make a big difference for shrapnel with large negative armor pen
|
||||
actual_chance += pen_mod // doing the armor pen as a separate calc just in case this ever gets expanded on
|
||||
if(actual_chance <= 0)
|
||||
victim.visible_message("<span class='danger'>[weapon] bounces off [victim]'s armor!</span>", "<span class='notice'>[weapon] bounces off your armor!</span>", vision_distance = COMBAT_MESSAGE_RANGE)
|
||||
return
|
||||
|
||||
var/roll_embed = prob(actual_chance)
|
||||
var/pass = forced || ((((throwingdatum ? throwingdatum.speed : weapon.throw_speed) >= EMBED_THROWSPEED_THRESHOLD) || ignore_throwspeed_threshold) && roll_embed && (!HAS_TRAIT(victim, TRAIT_AUTO_CATCH_ITEM) || victim.incapacitated() || victim.get_active_held_item()))
|
||||
if(!pass)
|
||||
return
|
||||
|
||||
var/obj/item/bodypart/limb = victim.get_bodypart(hit_zone) || pick(victim.bodyparts)
|
||||
victim.AddComponent(/datum/component/embedded,\
|
||||
weapon,\
|
||||
throwingdatum,\
|
||||
part = limb,\
|
||||
embed_chance = embed_chance,\
|
||||
fall_chance = fall_chance,\
|
||||
pain_chance = pain_chance,\
|
||||
pain_mult = pain_mult,\
|
||||
remove_pain_mult = remove_pain_mult,\
|
||||
rip_time = rip_time,\
|
||||
ignore_throwspeed_threshold = ignore_throwspeed_threshold,\
|
||||
jostle_chance = jostle_chance,\
|
||||
jostle_pain_mult = jostle_pain_mult,\
|
||||
pain_stam_pct = pain_stam_pct,\
|
||||
embed_chance_turf_mod = embed_chance_turf_mod)
|
||||
|
||||
return TRUE
|
||||
|
||||
/// We need the hit_zone if we're embedding into a human, so this proc only handles if we're embedding into a turf
|
||||
/datum/element/embed/proc/checkEmbedOther(obj/item/weapon, turf/closed/hit, datum/thrownthing/throwingdatum, forced=FALSE)
|
||||
if(!istype(hit))
|
||||
return
|
||||
|
||||
var/chance = embed_chance + embed_chance_turf_mod
|
||||
if(iswallturf(hit))
|
||||
var/turf/closed/wall/W = hit
|
||||
chance += 2 * (W.hardness - STANDARD_WALL_HARDNESS)
|
||||
|
||||
if(!forced && chance <= 0 || embed_chance_turf_mod <= -100)
|
||||
return
|
||||
|
||||
var/pass = ((((throwingdatum ? throwingdatum.speed : weapon.throw_speed) >= EMBED_THROWSPEED_THRESHOLD) || ignore_throwspeed_threshold) && prob(chance))
|
||||
if(!pass)
|
||||
return
|
||||
|
||||
hit.AddComponent(/datum/component/embedded,\
|
||||
weapon,\
|
||||
throwingdatum,\
|
||||
embed_chance = embed_chance,\
|
||||
fall_chance = fall_chance,\
|
||||
pain_chance = pain_chance,\
|
||||
pain_mult = pain_mult,\
|
||||
remove_pain_mult = remove_pain_mult,\
|
||||
rip_time = rip_time,\
|
||||
ignore_throwspeed_threshold = ignore_throwspeed_threshold,\
|
||||
jostle_chance = jostle_chance,\
|
||||
jostle_pain_mult = jostle_pain_mult,\
|
||||
pain_stam_pct = pain_stam_pct,\
|
||||
embed_chance_turf_mod = embed_chance_turf_mod)
|
||||
|
||||
return TRUE
|
||||
|
||||
///A different embed element has been attached, so we'll detach and let them handle things
|
||||
/datum/element/embed/proc/severancePackage(obj/item/weapon, datum/element/E)
|
||||
if(istype(E, /datum/element/embed))
|
||||
Detach(weapon)
|
||||
|
||||
///If we don't want to be embeddable anymore (deactivating an e-dagger for instance)
|
||||
/datum/element/embed/proc/detachFromWeapon(obj/weapon)
|
||||
Detach(weapon)
|
||||
|
||||
///Someone inspected our embeddable item
|
||||
/datum/element/embed/proc/examined(obj/item/I, mob/user, list/examine_list)
|
||||
if(I.isEmbedHarmless())
|
||||
examine_list += "[I] feels sticky, and could probably get stuck to someone if thrown properly!"
|
||||
else
|
||||
examine_list += "[I] has a fine point, and could probably embed in someone if thrown properly!"
|
||||
|
||||
/**
|
||||
* checkEmbedProjectile() is what we get when a projectile with a defined shrapnel_type impacts a target.
|
||||
*
|
||||
* If we hit a valid target (carbon or closed turf), we create the shrapnel_type object and immediately call tryEmbed() on it, targeting what we impacted. That will lead
|
||||
* it to call tryForceEmbed() on its own embed element (it's out of our hands here, our projectile is done), where it will run through all the checks it needs to.
|
||||
*/
|
||||
/datum/element/embed/proc/checkEmbedProjectile(obj/item/projectile/P, atom/movable/firer, atom/hit, angle, hit_zone)
|
||||
if(!iscarbon(hit) && !isclosedturf(hit))
|
||||
Detach(P)
|
||||
return // we don't care
|
||||
|
||||
var/obj/item/payload = new payload_type(get_turf(hit))
|
||||
var/did_embed
|
||||
if(iscarbon(hit))
|
||||
var/mob/living/carbon/C = hit
|
||||
var/obj/item/bodypart/limb
|
||||
limb = C.get_bodypart(hit_zone)
|
||||
if(!limb)
|
||||
limb = C.get_bodypart()
|
||||
did_embed = payload.tryEmbed(limb)
|
||||
else
|
||||
did_embed = payload.tryEmbed(hit)
|
||||
|
||||
if(!did_embed)
|
||||
payload.failedEmbed()
|
||||
Detach(P)
|
||||
|
||||
/**
|
||||
* tryForceEmbed() is called here when we fire COMSIG_EMBED_TRY_FORCE from [/obj/item/proc/tryEmbed]. Mostly, this means we're a piece of shrapnel from a projectile that just impacted something, and we're trying to embed in it.
|
||||
*
|
||||
* The reason for this extra mucking about is avoiding having to do an extra hitby(), and annoying the target by impacting them once with the projectile, then again with the shrapnel (which likely represents said bullet), and possibly
|
||||
* AGAIN if we actually embed. This way, we save on at least one message. Runs the standard embed checks on the mob/turf.
|
||||
*
|
||||
* Arguments:
|
||||
* * I- what we're trying to embed, obviously
|
||||
* * target- what we're trying to shish-kabob, either a bodypart, a carbon, or a closed turf
|
||||
* * hit_zone- if our target is a carbon, try to hit them in this zone, if we don't have one, pick a random one. If our target is a bodypart, we already know where we're hitting.
|
||||
* * forced- if we want this to succeed 100%
|
||||
*/
|
||||
/datum/element/embed/proc/tryForceEmbed(obj/item/I, atom/target, hit_zone, forced=FALSE)
|
||||
var/obj/item/bodypart/limb
|
||||
var/mob/living/carbon/C
|
||||
var/turf/closed/T
|
||||
|
||||
if(!forced && !prob(embed_chance))
|
||||
return
|
||||
|
||||
if(iscarbon(target))
|
||||
C = target
|
||||
if(!hit_zone)
|
||||
limb = pick(C.bodyparts)
|
||||
hit_zone = limb.body_zone
|
||||
else if(isbodypart(target))
|
||||
limb = target
|
||||
hit_zone = limb.body_zone
|
||||
C = limb.owner
|
||||
else if(isclosedturf(target))
|
||||
T = target
|
||||
|
||||
if(C)
|
||||
return checkEmbedMob(I, C, hit_zone, forced=TRUE)
|
||||
else if(T)
|
||||
return checkEmbedOther(I, T, forced=TRUE)
|
||||
@@ -1,53 +0,0 @@
|
||||
#define EMBEDID "embed-[embed_chance]-[embedded_fall_chance]-[embedded_pain_chance]-[embedded_pain_multiplier]-[embedded_fall_pain_multiplier]-[embedded_impact_pain_multiplier]-[embedded_unsafe_removal_pain_multiplier]-[embedded_unsafe_removal_time]"
|
||||
|
||||
/proc/getEmbeddingBehavior(embed_chance = EMBED_CHANCE,
|
||||
embedded_fall_chance = EMBEDDED_ITEM_FALLOUT,
|
||||
embedded_pain_chance = EMBEDDED_PAIN_CHANCE,
|
||||
embedded_pain_multiplier = EMBEDDED_PAIN_MULTIPLIER,
|
||||
embedded_fall_pain_multiplier = EMBEDDED_FALL_PAIN_MULTIPLIER,
|
||||
embedded_impact_pain_multiplier = EMBEDDED_IMPACT_PAIN_MULTIPLIER,
|
||||
embedded_unsafe_removal_pain_multiplier = EMBEDDED_UNSAFE_REMOVAL_PAIN_MULTIPLIER,
|
||||
embedded_unsafe_removal_time = EMBEDDED_UNSAFE_REMOVAL_TIME)
|
||||
. = locate(EMBEDID)
|
||||
if (!.)
|
||||
. = new /datum/embedding_behavior(embed_chance, embedded_fall_chance, embedded_pain_chance, embedded_pain_multiplier, embedded_fall_pain_multiplier, embedded_impact_pain_multiplier, embedded_unsafe_removal_pain_multiplier, embedded_unsafe_removal_time)
|
||||
|
||||
/datum/embedding_behavior
|
||||
var/embed_chance
|
||||
var/embedded_fall_chance
|
||||
var/embedded_pain_chance
|
||||
var/embedded_pain_multiplier //The coefficient of multiplication for the damage this item does while embedded (this*w_class)
|
||||
var/embedded_fall_pain_multiplier //The coefficient of multiplication for the damage this item does when falling out of a limb (this*w_class)
|
||||
var/embedded_impact_pain_multiplier //The coefficient of multiplication for the damage this item does when first embedded (this*w_class)
|
||||
var/embedded_unsafe_removal_pain_multiplier //The coefficient of multiplication for the damage removing this without surgery causes (this*w_class)
|
||||
var/embedded_unsafe_removal_time //A time in ticks, multiplied by the w_class.
|
||||
|
||||
/datum/embedding_behavior/New(embed_chance = EMBED_CHANCE,
|
||||
embedded_fall_chance = EMBEDDED_ITEM_FALLOUT,
|
||||
embedded_pain_chance = EMBEDDED_PAIN_CHANCE,
|
||||
embedded_pain_multiplier = EMBEDDED_PAIN_MULTIPLIER,
|
||||
embedded_fall_pain_multiplier = EMBEDDED_FALL_PAIN_MULTIPLIER,
|
||||
embedded_impact_pain_multiplier = EMBEDDED_IMPACT_PAIN_MULTIPLIER,
|
||||
embedded_unsafe_removal_pain_multiplier = EMBEDDED_UNSAFE_REMOVAL_PAIN_MULTIPLIER,
|
||||
embedded_unsafe_removal_time = EMBEDDED_UNSAFE_REMOVAL_TIME)
|
||||
src.embed_chance = embed_chance
|
||||
src.embedded_fall_chance = embedded_fall_chance
|
||||
src.embedded_pain_chance = embedded_pain_chance
|
||||
src.embedded_pain_multiplier = embedded_pain_multiplier
|
||||
src.embedded_fall_pain_multiplier = embedded_fall_pain_multiplier
|
||||
src.embedded_impact_pain_multiplier = embedded_impact_pain_multiplier
|
||||
src.embedded_unsafe_removal_pain_multiplier = embedded_unsafe_removal_pain_multiplier
|
||||
src.embedded_unsafe_removal_time = embedded_unsafe_removal_time
|
||||
tag = EMBEDID
|
||||
|
||||
/datum/embedding_behavior/proc/setRating(embed_chance, embedded_fall_chance, embedded_pain_chance, embedded_pain_multiplier, embedded_fall_pain_multiplier, embedded_impact_pain_multiplier, embedded_unsafe_removal_pain_multiplier, embedded_unsafe_removal_time)
|
||||
return getEmbeddingBehavior((isnull(embed_chance) ? src.embed_chance : embed_chance),\
|
||||
(isnull(embedded_fall_chance) ? src.embedded_fall_chance : embedded_fall_chance),\
|
||||
(isnull(embedded_pain_chance) ? src.embedded_pain_chance : embedded_pain_chance),\
|
||||
(isnull(embedded_pain_multiplier) ? src.embedded_pain_multiplier : embedded_pain_multiplier),\
|
||||
(isnull(embedded_fall_pain_multiplier) ? src.embedded_fall_pain_multiplier : embedded_fall_pain_multiplier),\
|
||||
(isnull(embedded_impact_pain_multiplier) ? src.embedded_impact_pain_multiplier : embedded_impact_pain_multiplier),\
|
||||
(isnull(embedded_unsafe_removal_pain_multiplier) ? src.embedded_unsafe_removal_pain_multiplier : embedded_unsafe_removal_pain_multiplier),\
|
||||
(isnull(embedded_unsafe_removal_time) ? src.embedded_unsafe_removal_time : embedded_unsafe_removal_time))
|
||||
|
||||
#undef EMBEDID
|
||||
+2
-1
@@ -27,7 +27,8 @@ GLOBAL_LIST_INIT(huds, list(
|
||||
ANTAG_HUD_SOULLESS = new/datum/atom_hud/antag/hidden(),
|
||||
ANTAG_HUD_CLOCKWORK = new/datum/atom_hud/antag(),
|
||||
ANTAG_HUD_BROTHER = new/datum/atom_hud/antag/hidden(),
|
||||
ANTAG_HUD_BLOODSUCKER = new/datum/atom_hud/antag/bloodsucker()
|
||||
ANTAG_HUD_BLOODSUCKER = new/datum/atom_hud/antag/bloodsucker(),
|
||||
ANTAG_HUD_FUGITIVE = new/datum/atom_hud/antag()
|
||||
))
|
||||
|
||||
/datum/atom_hud
|
||||
|
||||
@@ -23,10 +23,14 @@
|
||||
var/end_sound
|
||||
var/chance
|
||||
var/volume = 100
|
||||
var/vary = FALSE
|
||||
var/max_loops
|
||||
var/direct
|
||||
var/extra_range = 0
|
||||
var/falloff
|
||||
|
||||
var/timerid
|
||||
var/init_timerid
|
||||
|
||||
/datum/looping_sound/New(list/_output_atoms=list(), start_immediately=FALSE, _direct=FALSE)
|
||||
if(!mid_sounds)
|
||||
@@ -47,13 +51,15 @@
|
||||
/datum/looping_sound/proc/start(atom/add_thing)
|
||||
if(add_thing)
|
||||
output_atoms |= add_thing
|
||||
if(timerid)
|
||||
if(timerid || init_timerid)
|
||||
return
|
||||
on_start()
|
||||
|
||||
/datum/looping_sound/proc/stop(atom/remove_thing)
|
||||
if(remove_thing)
|
||||
output_atoms -= remove_thing
|
||||
if(init_timerid)
|
||||
deltimer(init_timerid)
|
||||
if(!timerid)
|
||||
return
|
||||
on_stop()
|
||||
@@ -80,7 +86,7 @@
|
||||
if(direct)
|
||||
SEND_SOUND(thing, S)
|
||||
else
|
||||
playsound(thing, S, volume)
|
||||
playsound(thing, S, volume, vary, extra_range, falloff)
|
||||
|
||||
/datum/looping_sound/proc/get_sound(starttime, _mid_sounds)
|
||||
. = _mid_sounds || mid_sounds
|
||||
@@ -92,7 +98,7 @@
|
||||
if(start_sound)
|
||||
play(start_sound)
|
||||
start_wait = start_length
|
||||
addtimer(CALLBACK(src, .proc/sound_loop), start_wait, TIMER_CLIENT_TIME)
|
||||
init_timerid = addtimer(CALLBACK(src, .proc/sound_loop), start_wait, TIMER_CLIENT_TIME | TIMER_STOPPABLE)
|
||||
|
||||
/datum/looping_sound/proc/on_stop()
|
||||
if(end_sound)
|
||||
|
||||
@@ -6,8 +6,6 @@ Simple datum which is instanced once per type and is used for every object of sa
|
||||
/datum/material
|
||||
var/name = "material"
|
||||
var/desc = "its..stuff."
|
||||
///Var that's mostly used by science machines to identify specific materials, should most likely be phased out at some point
|
||||
var/id = "mat"
|
||||
///Base color of the material, is used for greyscale. Item isn't changed in color if this is null.
|
||||
var/color
|
||||
///Base alpha of the material, is used for greyscale icons.
|
||||
@@ -26,6 +24,20 @@ Simple datum which is instanced once per type and is used for every object of sa
|
||||
var/armor_modifiers = list("melee" = 1, "bullet" = 1, "laser" = 1, "energy" = 1, "bomb" = 1, "bio" = 1, "rad" = 1, "fire" = 1, "acid" = 1)
|
||||
///How beautiful is this material per unit?
|
||||
var/beauty_modifier = 0
|
||||
///Can be used to override the sound items make, lets add some SLOSHing.
|
||||
var/item_sound_override
|
||||
///Can be used to override the stepsound a turf makes. MORE SLOOOSH
|
||||
var/turf_sound_override
|
||||
///what texture icon state to overlay
|
||||
var/texture_layer_icon_state
|
||||
///a cached filter for the texture icon
|
||||
var/cached_texture_filter
|
||||
|
||||
/datum/material/New()
|
||||
. = ..()
|
||||
if(texture_layer_icon_state)
|
||||
var/texture_icon = icon('icons/materials/composite.dmi', texture_layer_icon_state)
|
||||
cached_texture_filter = filter(type="layer", icon=texture_icon, blend_mode = BLEND_INSET_OVERLAY)
|
||||
|
||||
///This proc is called when the material is added to an object.
|
||||
/datum/material/proc/on_applied(atom/source, amount, material_flags)
|
||||
@@ -34,16 +46,27 @@ Simple datum which is instanced once per type and is used for every object of sa
|
||||
source.add_atom_colour(color, FIXED_COLOUR_PRIORITY)
|
||||
if(alpha)
|
||||
source.alpha = alpha
|
||||
if(texture_layer_icon_state)
|
||||
ADD_KEEP_TOGETHER(source, MATERIAL_SOURCE(src))
|
||||
source.filters += cached_texture_filter
|
||||
|
||||
if(material_flags & MATERIAL_ADD_PREFIX)
|
||||
source.name = "[name] [source.name]"
|
||||
|
||||
if(istype(source, /obj)) //objs
|
||||
on_applied_obj(source, amount, material_flags)
|
||||
|
||||
if(beauty_modifier)
|
||||
addtimer(CALLBACK(source, /datum.proc/_AddElement, list(/datum/element/beauty, beauty_modifier * amount)), 0)
|
||||
|
||||
if(istype(source, /obj)) //objs
|
||||
on_applied_obj(source, amount, material_flags)
|
||||
|
||||
else if(isturf(source, /turf)) //turfs
|
||||
on_applied_turf(source, amount, material_flags)
|
||||
|
||||
source.mat_update_desc(src)
|
||||
|
||||
///This proc is called when a material updates an object's description
|
||||
/atom/proc/mat_update_desc(/datum/material/mat)
|
||||
return
|
||||
///This proc is called when the material is added to an object specifically.
|
||||
/datum/material/proc/on_applied_obj(var/obj/o, amount, material_flags)
|
||||
if(material_flags & MATERIAL_AFFECT_STATISTICS)
|
||||
@@ -61,6 +84,24 @@ Simple datum which is instanced once per type and is used for every object of sa
|
||||
for(var/i in current_armor)
|
||||
temp_armor_list[i] = current_armor[i] * armor_modifiers[i]
|
||||
o.armor = getArmor(arglist(temp_armor_list))
|
||||
if(!isitem(o))
|
||||
return
|
||||
var/obj/item/I = o
|
||||
if(!item_sound_override)
|
||||
return
|
||||
I.hitsound = item_sound_override
|
||||
I.usesound = item_sound_override
|
||||
I.throwhitsound = item_sound_override
|
||||
|
||||
/datum/material/proc/on_applied_turf(var/turf/T, amount, material_flags)
|
||||
if(isopenturf(T))
|
||||
if(!turf_sound_override)
|
||||
return
|
||||
var/turf/open/O = T
|
||||
O.footstep = turf_sound_override
|
||||
O.barefootstep = turf_sound_override
|
||||
O.clawfootstep = turf_sound_override
|
||||
O.heavyfootstep = turf_sound_override
|
||||
|
||||
///This proc is called when the material is removed from an object.
|
||||
/datum/material/proc/on_removed(atom/source, material_flags)
|
||||
@@ -68,6 +109,9 @@ Simple datum which is instanced once per type and is used for every object of sa
|
||||
if(color)
|
||||
source.remove_atom_colour(FIXED_COLOUR_PRIORITY, color)
|
||||
source.alpha = initial(source.alpha)
|
||||
if(texture_layer_icon_state)
|
||||
source.filters -= cached_texture_filter
|
||||
REMOVE_KEEP_TOGETHER(source, MATERIAL_SOURCE(src))
|
||||
|
||||
if(material_flags & MATERIAL_ADD_PREFIX)
|
||||
source.name = initial(source.name)
|
||||
@@ -75,10 +119,16 @@ Simple datum which is instanced once per type and is used for every object of sa
|
||||
if(istype(source, /obj)) //objs
|
||||
on_removed_obj(source, material_flags)
|
||||
|
||||
else if(istype(source, /turf)) //turfs
|
||||
on_removed_turf(source, material_flags)
|
||||
|
||||
///This proc is called when the material is removed from an object specifically.
|
||||
/datum/material/proc/on_removed_obj(var/obj/o, amount, material_flags)
|
||||
/datum/material/proc/on_removed_obj(obj/o, material_flags)
|
||||
if(material_flags & MATERIAL_AFFECT_STATISTICS)
|
||||
var/new_max_integrity = initial(o.max_integrity)
|
||||
o.modify_max_integrity(new_max_integrity)
|
||||
o.force = initial(o.force)
|
||||
o.throwforce = initial(o.throwforce)
|
||||
|
||||
/datum/material/proc/on_removed_turf(turf/T, material_flags)
|
||||
return
|
||||
|
||||
@@ -1,21 +1,19 @@
|
||||
///Has no special properties.
|
||||
/datum/material/iron
|
||||
name = "iron"
|
||||
id = "iron"
|
||||
desc = "Common iron ore often found in sedimentary and igneous layers of the crust."
|
||||
color = "#878687"
|
||||
categories = list(MAT_CATEGORY_ORE = TRUE, MAT_CATEGORY_RIGID = TRUE)
|
||||
categories = list(MAT_CATEGORY_ORE = TRUE, MAT_CATEGORY_RIGID = TRUE, MAT_CATEGORY_BASE_RECIPES = TRUE)
|
||||
sheet_type = /obj/item/stack/sheet/metal
|
||||
value_per_unit = 0.0025
|
||||
|
||||
///Breaks extremely easily but is transparent.
|
||||
/datum/material/glass
|
||||
name = "glass"
|
||||
id = "glass"
|
||||
desc = "Glass forged by melting sand."
|
||||
color = "#88cdf1"
|
||||
alpha = 150
|
||||
categories = list(MAT_CATEGORY_RIGID = TRUE)
|
||||
categories = list(MAT_CATEGORY_RIGID = TRUE, MAT_CATEGORY_BASE_RECIPES = TRUE)
|
||||
integrity_modifier = 0.1
|
||||
sheet_type = /obj/item/stack/sheet/glass
|
||||
value_per_unit = 0.0025
|
||||
@@ -30,10 +28,9 @@ Unless you know what you're doing, only use the first three numbers. They're in
|
||||
///Has no special properties. Could be good against vampires in the future perhaps.
|
||||
/datum/material/silver
|
||||
name = "silver"
|
||||
id = "silver"
|
||||
desc = "Silver"
|
||||
color = list(255/255, 284/255, 302/255,0, 0,0,0,0, 0,0,0,0, 0,0,0,1, 0,0,0,0)
|
||||
categories = list(MAT_CATEGORY_ORE = TRUE, MAT_CATEGORY_RIGID = TRUE)
|
||||
categories = list(MAT_CATEGORY_ORE = TRUE, MAT_CATEGORY_RIGID = TRUE, MAT_CATEGORY_BASE_RECIPES = TRUE)
|
||||
sheet_type = /obj/item/stack/sheet/mineral/silver
|
||||
value_per_unit = 0.025
|
||||
beauty_modifier = 0.075
|
||||
@@ -41,11 +38,10 @@ Unless you know what you're doing, only use the first three numbers. They're in
|
||||
///Slight force increase
|
||||
/datum/material/gold
|
||||
name = "gold"
|
||||
id = "gold"
|
||||
desc = "Gold"
|
||||
color = list(340/255, 240/255, 50/255,0, 0,0,0,0, 0,0,0,0, 0,0,0,1, 0,0,0,0) //gold is shiny, but not as bright as bananium
|
||||
strength_modifier = 1.2
|
||||
categories = list(MAT_CATEGORY_ORE = TRUE, MAT_CATEGORY_RIGID = TRUE)
|
||||
categories = list(MAT_CATEGORY_ORE = TRUE, MAT_CATEGORY_RIGID = TRUE, MAT_CATEGORY_BASE_RECIPES = TRUE)
|
||||
sheet_type = /obj/item/stack/sheet/mineral/gold
|
||||
value_per_unit = 0.0625
|
||||
beauty_modifier = 0.15
|
||||
@@ -54,11 +50,10 @@ Unless you know what you're doing, only use the first three numbers. They're in
|
||||
///Has no special properties
|
||||
/datum/material/diamond
|
||||
name = "diamond"
|
||||
id = "diamond"
|
||||
desc = "Highly pressurized carbon"
|
||||
color = list(48/255, 272/255, 301/255,0, 0,0,0,0, 0,0,0,0, 0,0,0,1, 0,0,0,0)
|
||||
alpha = 132
|
||||
categories = list(MAT_CATEGORY_ORE = TRUE, MAT_CATEGORY_RIGID = TRUE)
|
||||
categories = list(MAT_CATEGORY_ORE = TRUE, MAT_CATEGORY_RIGID = TRUE, MAT_CATEGORY_BASE_RECIPES = TRUE)
|
||||
sheet_type = /obj/item/stack/sheet/mineral/diamond
|
||||
value_per_unit = 0.25
|
||||
beauty_modifier = 0.3
|
||||
@@ -67,10 +62,9 @@ Unless you know what you're doing, only use the first three numbers. They're in
|
||||
///Is slightly radioactive
|
||||
/datum/material/uranium
|
||||
name = "uranium"
|
||||
id = "uranium"
|
||||
desc = "Uranium"
|
||||
color = rgb(48, 237, 26)
|
||||
categories = list(MAT_CATEGORY_ORE = TRUE, MAT_CATEGORY_RIGID = TRUE)
|
||||
categories = list(MAT_CATEGORY_ORE = TRUE, MAT_CATEGORY_RIGID = TRUE, MAT_CATEGORY_BASE_RECIPES = TRUE)
|
||||
sheet_type = /obj/item/stack/sheet/mineral/uranium
|
||||
value_per_unit = 0.05
|
||||
beauty_modifier = 0.3 //It shines so beautiful
|
||||
@@ -88,10 +82,9 @@ Unless you know what you're doing, only use the first three numbers. They're in
|
||||
///Adds firestacks on hit (Still needs support to turn into gas on destruction)
|
||||
/datum/material/plasma
|
||||
name = "plasma"
|
||||
id = "plasma"
|
||||
desc = "Isn't plasma a state of matter? Oh whatever."
|
||||
color = list(298/255, 46/255, 352/255,0, 0,0,0,0, 0,0,0,0, 0,0,0,1, 0,0,0,0)
|
||||
categories = list(MAT_CATEGORY_ORE = TRUE, MAT_CATEGORY_RIGID = TRUE)
|
||||
categories = list(MAT_CATEGORY_ORE = TRUE, MAT_CATEGORY_RIGID = TRUE, MAT_CATEGORY_BASE_RECIPES = TRUE)
|
||||
sheet_type = /obj/item/stack/sheet/mineral/plasma
|
||||
value_per_unit = 0.1
|
||||
beauty_modifier = 0.15
|
||||
@@ -111,7 +104,6 @@ Unless you know what you're doing, only use the first three numbers. They're in
|
||||
///Can cause bluespace effects on use. (Teleportation) (Not yet implemented)
|
||||
/datum/material/bluespace
|
||||
name = "bluespace crystal"
|
||||
id = "bluespace_crystal"
|
||||
desc = "Crystals with bluespace properties"
|
||||
color = list(119/255, 217/255, 396/255,0, 0,0,0,0, 0,0,0,0, 0,0,0,1, 0,0,0,0)
|
||||
alpha = 200
|
||||
@@ -123,10 +115,9 @@ Unless you know what you're doing, only use the first three numbers. They're in
|
||||
///Honks and slips
|
||||
/datum/material/bananium
|
||||
name = "bananium"
|
||||
id = "bananium"
|
||||
desc = "Material with hilarious properties"
|
||||
color = list(460/255, 464/255, 0, 0, 0,0,0,0, 0,0,0,0, 0,0,0,1, 0,0,0,0) //obnoxiously bright yellow
|
||||
categories = list(MAT_CATEGORY_ORE = TRUE, MAT_CATEGORY_RIGID = TRUE)
|
||||
categories = list(MAT_CATEGORY_ORE = TRUE, MAT_CATEGORY_RIGID = TRUE, MAT_CATEGORY_BASE_RECIPES = TRUE)
|
||||
sheet_type = /obj/item/stack/sheet/mineral/bananium
|
||||
value_per_unit = 0.5
|
||||
beauty_modifier = 0.5
|
||||
@@ -146,11 +137,10 @@ Unless you know what you're doing, only use the first three numbers. They're in
|
||||
///Mediocre force increase
|
||||
/datum/material/titanium
|
||||
name = "titanium"
|
||||
id = "titanium"
|
||||
desc = "Titanium"
|
||||
color = "#b3c0c7"
|
||||
strength_modifier = 1.3
|
||||
categories = list(MAT_CATEGORY_ORE = TRUE, MAT_CATEGORY_RIGID = TRUE)
|
||||
categories = list(MAT_CATEGORY_ORE = TRUE, MAT_CATEGORY_RIGID = TRUE, MAT_CATEGORY_BASE_RECIPES = TRUE)
|
||||
sheet_type = /obj/item/stack/sheet/mineral/titanium
|
||||
value_per_unit = 0.0625
|
||||
beauty_modifier = 0.05
|
||||
@@ -158,11 +148,10 @@ Unless you know what you're doing, only use the first three numbers. They're in
|
||||
|
||||
/datum/material/runite
|
||||
name = "runite"
|
||||
id = "runite"
|
||||
desc = "Runite"
|
||||
color = "#3F9995"
|
||||
strength_modifier = 1.3
|
||||
categories = list(MAT_CATEGORY_RIGID = TRUE)
|
||||
categories = list(MAT_CATEGORY_RIGID = TRUE, MAT_CATEGORY_BASE_RECIPES = TRUE)
|
||||
sheet_type = /obj/item/stack/sheet/mineral/runite
|
||||
beauty_modifier = 0.5
|
||||
armor_modifiers = list("melee" = 1.35, "bullet" = 2, "laser" = 0.5, "energy" = 1.25, "bomb" = 1.25, "bio" = 1, "rad" = 1, "fire" = 1.4, "acid" = 1) //rune is weak against magic lasers but strong against bullets. This is the combat triangle.
|
||||
@@ -170,7 +159,6 @@ Unless you know what you're doing, only use the first three numbers. They're in
|
||||
///Force decrease
|
||||
/datum/material/plastic
|
||||
name = "plastic"
|
||||
id = "plastic"
|
||||
desc = "Plastic"
|
||||
color = "#caccd9"
|
||||
strength_modifier = 0.85
|
||||
@@ -182,7 +170,6 @@ Unless you know what you're doing, only use the first three numbers. They're in
|
||||
///Force decrease and mushy sound effect. (Not yet implemented)
|
||||
/datum/material/biomass
|
||||
name = "biomass"
|
||||
id = "biomass"
|
||||
desc = "Organic matter"
|
||||
color = "#735b4d"
|
||||
strength_modifier = 0.8
|
||||
@@ -190,12 +177,11 @@ Unless you know what you're doing, only use the first three numbers. They're in
|
||||
|
||||
/datum/material/wood
|
||||
name = "wood"
|
||||
id = "wood"
|
||||
desc = "Flexible, durable, but flamable. Hard to come across in space."
|
||||
color = "#bb8e53"
|
||||
strength_modifier = 0.5
|
||||
sheet_type = /obj/item/stack/sheet/mineral/wood
|
||||
categories = list(MAT_CATEGORY_RIGID = TRUE)
|
||||
categories = list(MAT_CATEGORY_RIGID = TRUE, MAT_CATEGORY_BASE_RECIPES = TRUE)
|
||||
value_per_unit = 0.06
|
||||
beauty_modifier = 0.1
|
||||
armor_modifiers = list("melee" = 1.1, "bullet" = 1.1, "laser" = 0.4, "energy" = 0.4, "bomb" = 1, "bio" = 0.2, "rad" = 0, "fire" = 0, "acid" = 0.3)
|
||||
@@ -215,11 +201,10 @@ Unless you know what you're doing, only use the first three numbers. They're in
|
||||
///Stronk force increase
|
||||
/datum/material/adamantine
|
||||
name = "adamantine"
|
||||
id = "adamantine"
|
||||
desc = "A powerful material made out of magic, I mean science!"
|
||||
color = "#6d7e8e"
|
||||
strength_modifier = 1.5
|
||||
categories = list(MAT_CATEGORY_RIGID = TRUE)
|
||||
categories = list(MAT_CATEGORY_RIGID = TRUE, MAT_CATEGORY_BASE_RECIPES = TRUE)
|
||||
sheet_type = /obj/item/stack/sheet/mineral/adamantine
|
||||
value_per_unit = 0.25
|
||||
beauty_modifier = 0.4
|
||||
@@ -228,10 +213,9 @@ Unless you know what you're doing, only use the first three numbers. They're in
|
||||
///RPG Magic. (Admin only)
|
||||
/datum/material/mythril
|
||||
name = "mythril"
|
||||
id = "mythril"
|
||||
desc = "How this even exists is byond me"
|
||||
color = "#f2d5d7"
|
||||
categories = list(MAT_CATEGORY_RIGID = TRUE)
|
||||
categories = list(MAT_CATEGORY_RIGID = TRUE, MAT_CATEGORY_BASE_RECIPES = TRUE)
|
||||
sheet_type = /obj/item/stack/sheet/mineral/mythril
|
||||
value_per_unit = 0.75
|
||||
beauty_modifier = 0.5
|
||||
@@ -246,3 +230,134 @@ Unless you know what you're doing, only use the first three numbers. They're in
|
||||
. = ..()
|
||||
if(istype(source, /obj/item))
|
||||
qdel(source.GetComponent(/datum/component/fantasy))
|
||||
|
||||
//I don't like sand. It's coarse, and rough, and irritating, and it gets everywhere.
|
||||
/datum/material/sand
|
||||
name = "sand"
|
||||
desc = "You know, it's amazing just how structurally sound sand can be."
|
||||
color = "#EDC9AF"
|
||||
categories = list(MAT_CATEGORY_RIGID = TRUE, MAT_CATEGORY_BASE_RECIPES = TRUE)
|
||||
sheet_type = /obj/item/stack/sheet/sandblock
|
||||
value_per_unit = 0.001
|
||||
strength_modifier = 0.5
|
||||
integrity_modifier = 0.1
|
||||
armor_modifiers = list("melee" = 0.25, "bullet" = 0.25, "laser" = 1.25, "energy" = 0.25, "bomb" = 0.25, "bio" = 0.25, "rad" = 1.5, "fire" = 1.5, "acid" = 1.5)
|
||||
beauty_modifier = 0.25
|
||||
turf_sound_override = FOOTSTEP_SAND
|
||||
texture_layer_icon_state = "sand"
|
||||
|
||||
//And now for our lavaland dwelling friends, sand, but in stone form! Truly revolutionary.
|
||||
/datum/material/sandstone
|
||||
name = "sandstone"
|
||||
desc = "Bialtaakid 'ant taerif ma hdha."
|
||||
color = "#B77D31"
|
||||
categories = list(MAT_CATEGORY_RIGID = TRUE, MAT_CATEGORY_BASE_RECIPES = TRUE)
|
||||
sheet_type = /obj/item/stack/sheet/mineral/sandstone
|
||||
value_per_unit = 0.0025
|
||||
armor_modifiers = list("melee" = 0.5, "bullet" = 0.5, "laser" = 1.25, "energy" = 0.5, "bomb" = 0.5, "bio" = 0.25, "rad" = 1.5, "fire" = 1.5, "acid" = 1.5)
|
||||
beauty_modifier = 0.3
|
||||
turf_sound_override = FOOTSTEP_WOOD
|
||||
texture_layer_icon_state = "brick"
|
||||
|
||||
/datum/material/snow
|
||||
name = "snow"
|
||||
desc = "There's no business like snow business."
|
||||
color = "#FFFFFF"
|
||||
categories = list(MAT_CATEGORY_RIGID = TRUE, MAT_CATEGORY_BASE_RECIPES = TRUE)
|
||||
sheet_type = /obj/item/stack/sheet/mineral/snow
|
||||
value_per_unit = 0.0025
|
||||
armor_modifiers = list("melee" = 0.25, "bullet" = 0.25, "laser" = 0.25, "energy" = 0.25, "bomb" = 0.25, "bio" = 0.25, "rad" = 1.5, "fire" = 0.25, "acid" = 1.5)
|
||||
beauty_modifier = 0.3
|
||||
turf_sound_override = FOOTSTEP_SAND
|
||||
texture_layer_icon_state = "sand"
|
||||
|
||||
/datum/material/runedmetal
|
||||
name = "runed metal"
|
||||
desc = "Mir'ntrath barhah Nar'sie."
|
||||
color = "#3C3434"
|
||||
categories = list(MAT_CATEGORY_RIGID = TRUE, MAT_CATEGORY_BASE_RECIPES = TRUE)
|
||||
sheet_type = /obj/item/stack/sheet/runed_metal
|
||||
value_per_unit = 0.75
|
||||
armor_modifiers = list("melee" = 1.2, "bullet" = 1.2, "laser" = 1, "energy" = 1, "bomb" = 1.2, "bio" = 1.2, "rad" = 1.5, "fire" = 1.5, "acid" = 1.5)
|
||||
beauty_modifier = -0.15
|
||||
texture_layer_icon_state = "runed"
|
||||
|
||||
/datum/material/bronze
|
||||
name = "bronze"
|
||||
desc = "Clock Cult? Never heard of it."
|
||||
color = "#92661A"
|
||||
categories = list(MAT_CATEGORY_RIGID = TRUE, MAT_CATEGORY_BASE_RECIPES = TRUE)
|
||||
sheet_type = /obj/item/stack/tile/bronze
|
||||
value_per_unit = 0.025
|
||||
armor_modifiers = list("melee" = 1, "bullet" = 1, "laser" = 1, "energy" = 1, "bomb" = 1, "bio" = 1, "rad" = 1.5, "fire" = 1.5, "acid" = 1.5)
|
||||
beauty_modifier = 0.2
|
||||
|
||||
/datum/material/paper
|
||||
name = "paper"
|
||||
desc = "Ten thousand folds of pure starchy power."
|
||||
color = "#E5DCD5"
|
||||
categories = list(MAT_CATEGORY_RIGID = TRUE, MAT_CATEGORY_BASE_RECIPES = TRUE)
|
||||
sheet_type = /obj/item/stack/sheet/paperframes
|
||||
value_per_unit = 0.0025
|
||||
armor_modifiers = list("melee" = 0.1, "bullet" = 0.1, "laser" = 0.1, "energy" = 0.1, "bomb" = 0.1, "bio" = 0.1, "rad" = 1.5, "fire" = 0, "acid" = 1.5)
|
||||
beauty_modifier = 0.3
|
||||
turf_sound_override = FOOTSTEP_SAND
|
||||
texture_layer_icon_state = "paper"
|
||||
|
||||
/datum/material/paper/on_applied_obj(obj/source, amount, material_flags)
|
||||
. = ..()
|
||||
if(material_flags & MATERIAL_AFFECT_STATISTICS)
|
||||
var/obj/paper = source
|
||||
paper.resistance_flags |= FLAMMABLE
|
||||
paper.obj_flags |= UNIQUE_RENAME
|
||||
|
||||
/datum/material/paper/on_removed_obj(obj/source, material_flags)
|
||||
if(material_flags & MATERIAL_AFFECT_STATISTICS)
|
||||
var/obj/paper = source
|
||||
paper.resistance_flags &= ~FLAMMABLE
|
||||
return ..()
|
||||
|
||||
/datum/material/cardboard
|
||||
name = "cardboard"
|
||||
desc = "They say cardboard is used by hobos to make incredible things."
|
||||
color = "#5F625C"
|
||||
categories = list(MAT_CATEGORY_RIGID = TRUE, MAT_CATEGORY_BASE_RECIPES = TRUE)
|
||||
sheet_type = /obj/item/stack/sheet/cardboard
|
||||
value_per_unit = 0.003
|
||||
armor_modifiers = list("melee" = 0.25, "bullet" = 0.25, "laser" = 0.25, "energy" = 0.25, "bomb" = 0.25, "bio" = 0.25, "rad" = 1.5, "fire" = 0, "acid" = 1.5)
|
||||
beauty_modifier = -0.1
|
||||
|
||||
/datum/material/cardboard/on_applied_obj(obj/source, amount, material_flags)
|
||||
. = ..()
|
||||
if(material_flags & MATERIAL_AFFECT_STATISTICS)
|
||||
var/obj/cardboard = source
|
||||
cardboard.resistance_flags |= FLAMMABLE
|
||||
cardboard.obj_flags |= UNIQUE_RENAME
|
||||
|
||||
/datum/material/cardboard/on_removed_obj(obj/source, material_flags)
|
||||
if(material_flags & MATERIAL_AFFECT_STATISTICS)
|
||||
var/obj/cardboard = source
|
||||
cardboard.resistance_flags &= ~FLAMMABLE
|
||||
return ..()
|
||||
|
||||
/datum/material/bone
|
||||
name = "bone"
|
||||
desc = "Man, building with this will make you the coolest caveman on the block."
|
||||
color = "#e3dac9"
|
||||
categories = list(MAT_CATEGORY_RIGID = TRUE, MAT_CATEGORY_BASE_RECIPES = TRUE)
|
||||
sheet_type = /obj/item/stack/sheet/bone
|
||||
value_per_unit = 0.05
|
||||
armor_modifiers = list("melee" = 1.2, "bullet" = 0.75, "laser" = 0.75, "energy" = 1.2, "bomb" = 1, "bio" = 1, "rad" = 1.5, "fire" = 1.5, "acid" = 1.5)
|
||||
beauty_modifier = -0.2
|
||||
|
||||
/datum/material/bamboo
|
||||
name = "bamboo"
|
||||
desc = "If it's good enough for pandas, it's good enough for you."
|
||||
color = "#339933"
|
||||
categories = list(MAT_CATEGORY_RIGID = TRUE, MAT_CATEGORY_BASE_RECIPES = TRUE)
|
||||
sheet_type = /obj/item/stack/sheet/mineral/bamboo
|
||||
value_per_unit = 0.0025
|
||||
armor_modifiers = list("melee" = 0.5, "bullet" = 0.5, "laser" = 0.5, "energy" = 0.5, "bomb" = 0.5, "bio" = 0.51, "rad" = 1.5, "fire" = 0.5, "acid" = 1.5)
|
||||
beauty_modifier = 0.2
|
||||
turf_sound_override = FOOTSTEP_WOOD
|
||||
texture_layer_icon_state = "bamboo"
|
||||
|
||||
@@ -0,0 +1,32 @@
|
||||
///It's gross, gets the name of it's owner, and is all kinds of fucked up
|
||||
/datum/material/meat
|
||||
name = "meat"
|
||||
desc = "Meat"
|
||||
color = rgb(214, 67, 67)
|
||||
categories = list(MAT_CATEGORY_RIGID = TRUE, MAT_CATEGORY_BASE_RECIPES = TRUE)
|
||||
sheet_type = /obj/item/stack/sheet/meat
|
||||
value_per_unit = 0.05
|
||||
beauty_modifier = -0.3
|
||||
strength_modifier = 0.7
|
||||
armor_modifiers = list("melee" = 0.3, "bullet" = 0.3, "laser" = 1.2, "energy" = 1.2, "bomb" = 0.3, "bio" = 0, "rad" = 0.7, "fire" = 1, "acid" = 1)
|
||||
item_sound_override = 'sound/effects/meatslap.ogg'
|
||||
turf_sound_override = FOOTSTEP_MEAT
|
||||
texture_layer_icon_state = "meat"
|
||||
|
||||
/datum/material/meat/on_removed(atom/source, material_flags)
|
||||
. = ..()
|
||||
qdel(source.GetComponent(/datum/component/edible))
|
||||
|
||||
/datum/material/meat/on_applied_obj(obj/O, amount, material_flags)
|
||||
. = ..()
|
||||
O.obj_flags |= UNIQUE_RENAME //So you can name it after the person its made from, a depressing comprimise.
|
||||
make_edible(O, amount, material_flags)
|
||||
|
||||
/datum/material/meat/on_applied_turf(turf/T, amount, material_flags)
|
||||
. = ..()
|
||||
make_edible(T, amount, material_flags)
|
||||
|
||||
/datum/material/meat/proc/make_edible(atom/source, amount, material_flags)
|
||||
var/nutriment_count = 3 * (amount / MINERAL_MATERIAL_AMOUNT)
|
||||
var/oil_count = 2 * (amount / MINERAL_MATERIAL_AMOUNT)
|
||||
source.AddComponent(/datum/component/edible, list(/datum/reagent/consumable/nutriment = nutriment_count, /datum/reagent/consumable/cooking_oil = oil_count), null, RAW | MEAT | GROSS, null, 30, list("Fleshy"))
|
||||
@@ -0,0 +1,30 @@
|
||||
/datum/material/pizza
|
||||
name = "pizza"
|
||||
desc = "~Jamme, jamme, n'coppa, jamme ja! Jamme, jamme, n'coppa jamme ja, funi-culi funi-cala funi-culi funi-cala!! Jamme jamme ja funiculi funicula!~"
|
||||
color = "#FF9F23"
|
||||
categories = list(MAT_CATEGORY_RIGID = TRUE, MAT_CATEGORY_BASE_RECIPES = TRUE)
|
||||
sheet_type = /obj/item/stack/sheet/pizza
|
||||
value_per_unit = 0.05
|
||||
beauty_modifier = 0.1
|
||||
strength_modifier = 0.7
|
||||
armor_modifiers = list("melee" = 0.3, "bullet" = 0.3, "laser" = 1.2, "energy" = 1.2, "bomb" = 0.3, "bio" = 0, "rad" = 0.7, "fire" = 1, "acid" = 1)
|
||||
item_sound_override = 'sound/effects/meatslap.ogg'
|
||||
turf_sound_override = FOOTSTEP_MEAT
|
||||
texture_layer_icon_state = "pizza"
|
||||
|
||||
/datum/material/pizza/on_removed(atom/source, material_flags)
|
||||
. = ..()
|
||||
qdel(source.GetComponent(/datum/component/edible))
|
||||
|
||||
/datum/material/pizza/on_applied_obj(obj/O, amount, material_flags)
|
||||
. = ..()
|
||||
make_edible(O, amount, material_flags)
|
||||
|
||||
/datum/material/pizza/on_applied_turf(turf/T, amount, material_flags)
|
||||
. = ..()
|
||||
make_edible(T, amount, material_flags)
|
||||
|
||||
/datum/material/pizza/proc/make_edible(atom/source, amount, material_flags)
|
||||
var/nutriment_count = 3 * (amount / MINERAL_MATERIAL_AMOUNT)
|
||||
var/oil_count = 2 * (amount / MINERAL_MATERIAL_AMOUNT)
|
||||
source.AddComponent(/datum/component/edible, list(/datum/reagent/consumable/nutriment = nutriment_count, /datum/reagent/consumable/cooking_oil = oil_count), null, GRAIN | MEAT | DAIRY | VEGETABLES, null, 30, list("crust", "tomato", "cheese", "meat"))
|
||||
@@ -406,6 +406,8 @@
|
||||
w_class = WEIGHT_CLASS_SMALL
|
||||
sharpness = IS_SHARP
|
||||
var/mob/living/carbon/human/fired_by
|
||||
/// if we missed our target
|
||||
var/missed = TRUE
|
||||
|
||||
/obj/item/hardened_spike/Initialize(mapload, firedby)
|
||||
. = ..()
|
||||
@@ -413,13 +415,12 @@
|
||||
addtimer(CALLBACK(src, .proc/checkembedded), 5 SECONDS)
|
||||
|
||||
/obj/item/hardened_spike/proc/checkembedded()
|
||||
if(ishuman(loc))
|
||||
var/mob/living/carbon/human/embedtest = loc
|
||||
for(var/l in embedtest.bodyparts)
|
||||
var/obj/item/bodypart/limb = l
|
||||
if(src in limb.embedded_objects)
|
||||
return limb
|
||||
unembedded()
|
||||
if(missed)
|
||||
unembedded()
|
||||
|
||||
/obj/item/hardened_spike/embedded(atom/target)
|
||||
if(isbodypart(target))
|
||||
missed = FALSE
|
||||
|
||||
/obj/item/hardened_spike/unembedded()
|
||||
var/turf/T = get_turf(src)
|
||||
@@ -490,11 +491,7 @@
|
||||
|
||||
var/obj/item/bodypart/L = spikey.checkembedded()
|
||||
|
||||
L.embedded_objects -= spikey
|
||||
//this is where it would deal damage, if it transfers chems it removes itself so no damage
|
||||
spikey.forceMove(get_turf(L))
|
||||
transfered.visible_message("<span class='notice'>[spikey] falls out of [transfered]!</span>")
|
||||
if(!transfered.has_embedded_objects())
|
||||
transfered.clear_alert("embeddedobject")
|
||||
SEND_SIGNAL(transfered, COMSIG_CLEAR_MOOD_EVENT, "embedded")
|
||||
spikey.unembedded()
|
||||
|
||||
|
||||
@@ -162,6 +162,10 @@
|
||||
port_id = "pirate"
|
||||
can_be_bought = FALSE
|
||||
|
||||
/datum/map_template/shuttle/hunter
|
||||
port_id = "hunter"
|
||||
can_be_bought = FALSE
|
||||
|
||||
/datum/map_template/shuttle/ruin //For random shuttles in ruins
|
||||
port_id = "ruin"
|
||||
can_be_bought = FALSE
|
||||
@@ -458,6 +462,10 @@
|
||||
suffix = "whiteship_pod"
|
||||
name = "Salvage Pod"
|
||||
|
||||
/datum/map_template/shuttle/whiteship/cog
|
||||
suffix = "cog"
|
||||
name = "NT Prisoner Transport"
|
||||
|
||||
/datum/map_template/shuttle/cargo/box
|
||||
suffix = "box"
|
||||
name = "supply shuttle (Box)"
|
||||
@@ -613,3 +621,15 @@
|
||||
/datum/map_template/shuttle/snowdin/excavation
|
||||
suffix = "excavation"
|
||||
name = "Snowdin Excavation Elevator"
|
||||
|
||||
/datum/map_template/shuttle/hunter/space_cop
|
||||
suffix = "space_cop"
|
||||
name = "Police Spacevan"
|
||||
|
||||
/datum/map_template/shuttle/hunter/russian
|
||||
suffix = "russian"
|
||||
name = "Russian Cargo Ship"
|
||||
|
||||
/datum/map_template/shuttle/hunter/bounty
|
||||
suffix = "bounty"
|
||||
name = "Bounty Hunter Ship"
|
||||
|
||||
@@ -81,11 +81,11 @@
|
||||
owner.adjustStaminaLoss(-0.5) //reduce stamina loss by 0.5 per tick, 10 per 2 seconds
|
||||
if(human_owner && human_owner.drunkenness)
|
||||
human_owner.drunkenness *= 0.997 //reduce drunkenness by 0.3% per tick, 6% per 2 seconds
|
||||
if(prob(20))
|
||||
if(carbon_owner)
|
||||
carbon_owner.handle_dreams()
|
||||
if(prob(10) && owner.health > owner.crit_threshold)
|
||||
owner.emote("snore")
|
||||
if(carbon_owner && !carbon_owner.dreaming && prob(2))
|
||||
carbon_owner.dream()
|
||||
// 2% per second, tick interval is in deciseconds
|
||||
if(prob((tick_interval+1) * 0.2) && owner.health > owner.crit_threshold)
|
||||
owner.emote("snore")
|
||||
|
||||
/datum/status_effect/staggered
|
||||
id = "staggered"
|
||||
@@ -795,3 +795,44 @@ datum/status_effect/pacify
|
||||
name = "Genetic Breakdown"
|
||||
desc = "I don't feel so good. Your body can't handle the mutations! You have one minute to remove your mutations, or you will be met with a horrible fate."
|
||||
icon_state = "dna_melt"
|
||||
|
||||
/datum/status_effect/fake_virus
|
||||
id = "fake_virus"
|
||||
duration = 1800//3 minutes
|
||||
status_type = STATUS_EFFECT_REPLACE
|
||||
tick_interval = 1
|
||||
alert_type = null
|
||||
var/msg_stage = 0//so you dont get the most intense messages immediately
|
||||
|
||||
/datum/status_effect/fake_virus/tick()
|
||||
var/fake_msg = ""
|
||||
var/fake_emote = ""
|
||||
switch(msg_stage)
|
||||
if(0 to 300)
|
||||
if(prob(1))
|
||||
fake_msg = pick("<span class='warning'>[pick("Your head hurts.", "Your head pounds.")]</span>",
|
||||
"<span class='warning'>[pick("You're having difficulty breathing.", "Your breathing becomes heavy.")]</span>",
|
||||
"<span class='warning'>[pick("You feel dizzy.", "Your head spins.")]</span>",
|
||||
"<span notice='warning'>[pick("You swallow excess mucus.", "You lightly cough.")]</span>",
|
||||
"<span class='warning'>[pick("Your head hurts.", "Your mind blanks for a moment.")]</span>",
|
||||
"<span class='warning'>[pick("Your throat hurts.", "You clear your throat.")]</span>")
|
||||
if(301 to 600)
|
||||
if(prob(2))
|
||||
fake_msg = pick("<span class='warning'>[pick("Your head hurts a lot.", "Your head pounds incessantly.")]</span>",
|
||||
"<span class='warning'>[pick("Your windpipe feels like a straw.", "Your breathing becomes tremendously difficult.")]</span>",
|
||||
"<span class='warning'>You feel very [pick("dizzy","woozy","faint")].</span>",
|
||||
"<span class='warning'>[pick("You hear a ringing in your ear.", "Your ears pop.")]</span>",
|
||||
"<span class='warning'>You nod off for a moment.</span>")
|
||||
else
|
||||
if(prob(3))
|
||||
if(prob(50))// coin flip to throw a message or an emote
|
||||
fake_msg = pick("<span class='userdanger'>[pick("Your head hurts!", "You feel a burning knife inside your brain!", "A wave of pain fills your head!")]</span>",
|
||||
"<span class='userdanger'>[pick("Your lungs hurt!", "It hurts to breathe!")]</span>",
|
||||
"<span class='warning'>[pick("You feel nauseated.", "You feel like you're going to throw up!")]</span>")
|
||||
else
|
||||
fake_emote = pick("cough", "sniff", "sneeze")
|
||||
if(fake_emote)
|
||||
owner.emote(fake_emote)
|
||||
else if(fake_msg)
|
||||
to_chat(owner, fake_msg)
|
||||
msg_stage++
|
||||
|
||||
@@ -6,6 +6,7 @@
|
||||
var/id = "effect" //Used for screen alerts.
|
||||
var/duration = -1 //How long the status effect lasts in DECISECONDS. Enter -1 for an effect that never ends unless removed through some means.
|
||||
var/tick_interval = 10 //How many deciseconds between ticks, approximately. Leave at 10 for every second.
|
||||
var/next_tick //The scheduled time for the next tick.
|
||||
var/mob/living/owner //The mob affected by the status effect.
|
||||
var/on_remove_on_mob_delete = FALSE //if we call on_remove() when the mob is deleted
|
||||
var/examine_text //If defined, this text will appear when the mob is examined - to use he, she etc. use "SUBJECTPRONOUN" and replace it in the examines themselves
|
||||
@@ -31,7 +32,7 @@
|
||||
return
|
||||
if(duration != -1)
|
||||
duration = world.time + duration
|
||||
tick_interval = world.time + tick_interval
|
||||
next_tick = world.time + tick_interval
|
||||
if(alert_type)
|
||||
var/obj/screen/alert/status_effect/A = owner.throw_alert(id, alert_type)
|
||||
A.attached_effect = src //so the alert can reference us, if it needs to
|
||||
@@ -52,9 +53,9 @@
|
||||
if(!owner)
|
||||
qdel(src)
|
||||
return
|
||||
if(tick_interval < world.time)
|
||||
if(next_tick < world.time)
|
||||
tick()
|
||||
tick_interval = world.time + initial(tick_interval)
|
||||
next_tick = world.time + tick_interval
|
||||
if(duration != -1 && duration < world.time)
|
||||
qdel(src)
|
||||
|
||||
@@ -221,7 +222,7 @@
|
||||
threshold_crossed = FALSE //resets threshold effect if we fall below threshold so threshold effect can trigger again
|
||||
on_threshold_drop()
|
||||
if(stacks_added > 0)
|
||||
tick_interval += delay_before_decay //refreshes time until decay
|
||||
next_tick += delay_before_decay //refreshes time until decay
|
||||
stacks = min(stacks, max_stacks)
|
||||
status_overlay.icon_state = "[overlay_state][stacks]"
|
||||
status_underlay.icon_state = "[underlay_state][stacks]"
|
||||
|
||||
@@ -93,6 +93,13 @@
|
||||
/area/shuttle/abandoned/pod
|
||||
name = "Abandoned Ship Pod"
|
||||
|
||||
////////////////////////////Bounty Hunter Shuttles////////////////////////////
|
||||
/area/shuttle/hunter
|
||||
name = "Hunter Shuttle"
|
||||
dynamic_lighting = DYNAMIC_LIGHTING_DISABLED
|
||||
blob_allowed = FALSE
|
||||
canSmoothWithAreas = /area/shuttle/hunter
|
||||
|
||||
////////////////////////////Single-area shuttles////////////////////////////
|
||||
|
||||
/area/shuttle/transit
|
||||
@@ -103,6 +110,10 @@
|
||||
/area/shuttle/custom
|
||||
name = "Custom player shuttle"
|
||||
|
||||
/area/shuttle/custom/powered
|
||||
name = "Custom Powered player shuttle"
|
||||
requires_power = FALSE
|
||||
|
||||
/area/shuttle/arrival
|
||||
name = "Arrival Shuttle"
|
||||
unique = TRUE // SSjob refers to this area for latejoiners
|
||||
|
||||
+60
-24
@@ -8,6 +8,13 @@
|
||||
var/interaction_flags_atom = NONE
|
||||
var/datum/reagents/reagents = null
|
||||
|
||||
var/flags_ricochet = NONE
|
||||
|
||||
///When a projectile tries to ricochet off this atom, the projectile ricochet chance is multiplied by this
|
||||
var/ricochet_chance_mod = 1
|
||||
///When a projectile ricochets off this atom, it deals the normal damage * this modifier to this atom
|
||||
var/ricochet_damage_mod = 0.33
|
||||
|
||||
//This atom's HUD (med/sec, etc) images. Associative list.
|
||||
var/list/image/hud_list = null
|
||||
//HUD images that this atom can provide.
|
||||
@@ -41,6 +48,7 @@
|
||||
var/rad_insulation = RAD_NO_INSULATION
|
||||
|
||||
///The custom materials this atom is made of, used by a lot of things like furniture, walls, and floors (if I finish the functionality, that is.)
|
||||
///The list referenced by this var can be shared by multiple objects and should not be directly modified. Instead, use [set_custom_materials][/atom/proc/set_custom_materials].
|
||||
var/list/custom_materials
|
||||
///Bitfield for how the atom handles materials.
|
||||
var/material_flags = NONE
|
||||
@@ -107,11 +115,8 @@
|
||||
if (canSmoothWith)
|
||||
canSmoothWith = typelist("canSmoothWith", canSmoothWith)
|
||||
|
||||
var/temp_list = list()
|
||||
for(var/i in custom_materials)
|
||||
temp_list[SSmaterials.GetMaterialRef(i)] = custom_materials[i] //Get the proper instanced version
|
||||
custom_materials = null //Null the list to prepare for applying the materials properly
|
||||
set_custom_materials(temp_list)
|
||||
// apply materials properly from the default custom_materials value
|
||||
set_custom_materials(custom_materials)
|
||||
|
||||
ComponentInitialize()
|
||||
|
||||
@@ -141,8 +146,27 @@
|
||||
|
||||
return ..()
|
||||
|
||||
/**
|
||||
* Checks if a projectile should ricochet off of us. Projectiles get final say.
|
||||
* [__DEFINES/projectiles.dm] for return values.
|
||||
*/
|
||||
/atom/proc/check_projectile_ricochet(obj/item/projectile/P)
|
||||
return (flags_1 & DEFAULT_RICOCHET_1)? PROJECTILE_RICOCHET_YES : PROJECTILE_RICOCHET_NO
|
||||
|
||||
/atom/proc/handle_ricochet(obj/item/projectile/P)
|
||||
return
|
||||
var/turf/p_turf = get_turf(P)
|
||||
var/face_direction = get_dir(src, p_turf)
|
||||
var/face_angle = dir2angle(face_direction)
|
||||
var/incidence_s = GET_ANGLE_OF_INCIDENCE(face_angle, (P.Angle + 180))
|
||||
var/a_incidence_s = abs(incidence_s)
|
||||
if(a_incidence_s > 90 && a_incidence_s < 270)
|
||||
return FALSE
|
||||
if((P.flag in list("bullet", "bomb")) && P.ricochet_incidence_leeway)
|
||||
if((a_incidence_s < 90 && a_incidence_s < 90 - P.ricochet_incidence_leeway) || (a_incidence_s > 270 && a_incidence_s -270 > P.ricochet_incidence_leeway))
|
||||
return
|
||||
var/new_angle_s = SIMPLIFY_DEGREES(face_angle + incidence_s)
|
||||
P.setAngle(new_angle_s)
|
||||
return TRUE
|
||||
|
||||
/atom/proc/CanPass(atom/movable/mover, turf/target)
|
||||
return !density
|
||||
@@ -420,8 +444,10 @@
|
||||
return
|
||||
var/list/blood_dna = list()
|
||||
if(dna)
|
||||
blood_dna["color"] = list(dna.species.exotic_blood_color) //so when combined, the list grows with the number of colors
|
||||
blood_dna[dna.unique_enzymes] = dna.blood_type
|
||||
else
|
||||
blood_dna["color"] = list(BLOOD_COLOR_HUMAN)
|
||||
blood_dna["UNKNOWN DNA"] = "X*"
|
||||
return blood_dna
|
||||
|
||||
@@ -435,8 +461,10 @@
|
||||
if(!new_blood_dna)
|
||||
return FALSE
|
||||
LAZYINITLIST(blood_DNA) //if our list of DNA doesn't exist yet, initialise it.
|
||||
LAZYINITLIST(blood_DNA["color"])
|
||||
var/old_length = blood_DNA.len
|
||||
blood_DNA |= new_blood_dna
|
||||
blood_DNA["color"] += new_blood_dna["color"]
|
||||
if(blood_DNA.len == old_length)
|
||||
return FALSE
|
||||
return TRUE
|
||||
@@ -444,9 +472,12 @@
|
||||
//to add blood dna info to the object's blood_DNA list
|
||||
/atom/proc/transfer_blood_dna(list/blood_dna, list/datum/disease/diseases)
|
||||
LAZYINITLIST(blood_DNA)
|
||||
LAZYINITLIST(blood_dna["color"])
|
||||
|
||||
var/old_length = blood_DNA.len
|
||||
blood_DNA |= blood_dna
|
||||
if(blood_DNA.len > old_length)
|
||||
blood_DNA["color"] += blood_dna["color"]
|
||||
return TRUE
|
||||
//some new blood DNA was added
|
||||
|
||||
@@ -518,23 +549,22 @@
|
||||
|
||||
/atom/proc/blood_DNA_to_color()
|
||||
var/list/colors = list()//first we make a list of all bloodtypes present
|
||||
for(var/bloop in blood_DNA)
|
||||
if(colors[blood_DNA[bloop]])
|
||||
colors[blood_DNA[bloop]]++
|
||||
for(var/blood_color in blood_DNA["color"])
|
||||
if(colors[blood_color])
|
||||
colors[blood_color]++
|
||||
else
|
||||
colors[blood_DNA[bloop]] = 1
|
||||
colors[blood_color] = 1
|
||||
|
||||
var/final_rgb = BLOOD_COLOR_HUMAN //a default so we don't have white blood graphics if something messed up
|
||||
|
||||
if(colors.len)
|
||||
var/sum = 0 //this is all shitcode, but it works; trust me
|
||||
final_rgb = bloodtype_to_color(colors[1])
|
||||
final_rgb = colors[1]
|
||||
sum = colors[colors[1]]
|
||||
if(colors.len > 1)
|
||||
var/i = 2
|
||||
while(i <= colors.len)
|
||||
var/tmp = colors[colors[i]]
|
||||
final_rgb = BlendRGB(final_rgb, bloodtype_to_color(colors[i]), tmp/(tmp+sum))
|
||||
final_rgb = BlendRGB(final_rgb, colors[i], tmp/(tmp+sum))
|
||||
sum += tmp
|
||||
i++
|
||||
|
||||
@@ -846,6 +876,17 @@
|
||||
/atom/proc/GenerateTag()
|
||||
return
|
||||
|
||||
/**
|
||||
* Called after a shuttle is loaded **from map template initially**.
|
||||
*
|
||||
* @params
|
||||
* * port - Mobile port/shuttle
|
||||
* * dock - Stationary dock the shuttle's at
|
||||
* * idnum - ID number of the shuttle
|
||||
*/
|
||||
/atom/proc/connect_to_shuttle(obj/docking_port/mobile/port, obj/docking_port/stationary/dock, idnum, override=FALSE)
|
||||
return
|
||||
|
||||
// Generic logging helper
|
||||
/atom/proc/log_message(message, message_type, color=null, log_globally=TRUE)
|
||||
if(!log_globally)
|
||||
@@ -969,26 +1010,21 @@ Proc for attack log creation, because really why not
|
||||
|
||||
///Sets the custom materials for an item.
|
||||
/atom/proc/set_custom_materials(var/list/materials, multiplier = 1)
|
||||
|
||||
if(!materials)
|
||||
materials = custom_materials
|
||||
|
||||
if(custom_materials) //Only runs if custom materials existed at first. Should usually be the case but check anyways
|
||||
for(var/i in custom_materials)
|
||||
var/datum/material/custom_material = SSmaterials.GetMaterialRef(i)
|
||||
custom_material.on_removed(src, material_flags) //Remove the current materials
|
||||
|
||||
if(!length(materials))
|
||||
custom_materials = null
|
||||
return
|
||||
|
||||
custom_materials = list() //Reset the list
|
||||
if(material_flags & MATERIAL_EFFECTS)
|
||||
for(var/x in materials)
|
||||
var/datum/material/custom_material = SSmaterials.GetMaterialRef(x)
|
||||
custom_material.on_applied(src, materials[x] * multiplier * material_modifier, material_flags)
|
||||
|
||||
for(var/x in materials)
|
||||
var/datum/material/custom_material = SSmaterials.GetMaterialRef(x)
|
||||
|
||||
if(material_flags & MATERIAL_EFFECTS)
|
||||
custom_material.on_applied(src, materials[custom_material] * multiplier * material_modifier, material_flags)
|
||||
custom_materials[custom_material] += materials[x] * multiplier
|
||||
custom_materials = SSmaterials.FindOrCreateMaterialCombo(materials, multiplier)
|
||||
|
||||
/**
|
||||
* Returns true if this atom has gravity for the passed in turf
|
||||
|
||||
@@ -202,7 +202,7 @@
|
||||
icon_state = "moustacheg"
|
||||
clumsy_check = GRENADE_NONCLUMSY_FUMBLE
|
||||
|
||||
/obj/item/grenade/chem_grenade/teargas/moustache/prime()
|
||||
/obj/item/grenade/chem_grenade/teargas/moustache/prime(mob/living/lanced_by)
|
||||
var/list/check_later = list()
|
||||
for(var/mob/living/carbon/C in get_turf(src))
|
||||
check_later += C
|
||||
|
||||
@@ -288,7 +288,7 @@ datum/gang_item/clothing/shades //Addition: Why not have cool shades on a gang m
|
||||
name = "Fragmentation Grenade"
|
||||
id = "frag nade"
|
||||
cost = 5
|
||||
item_path = /obj/item/grenade/syndieminibomb/concussion/frag
|
||||
item_path = /obj/item/grenade/frag
|
||||
|
||||
/datum/gang_item/equipment/implant_breaker
|
||||
name = "Implant Breaker"
|
||||
|
||||
@@ -92,6 +92,8 @@ Class Procs:
|
||||
pressure_resistance = 15
|
||||
max_integrity = 200
|
||||
layer = BELOW_OBJ_LAYER //keeps shit coming out of the machine from ending up underneath it.
|
||||
flags_ricochet = RICOCHET_HARD
|
||||
ricochet_chance_mod = 0.3
|
||||
|
||||
anchored = TRUE
|
||||
interaction_flags_atom = INTERACT_ATOM_ATTACK_HAND | INTERACT_ATOM_UI_INTERACT
|
||||
|
||||
@@ -46,29 +46,16 @@
|
||||
"Dinnerware",
|
||||
"Imported"
|
||||
)
|
||||
var/list/allowed_materials = list(
|
||||
/datum/material/iron,
|
||||
/datum/material/glass,
|
||||
/datum/material/gold,
|
||||
/datum/material/silver,
|
||||
/datum/material/diamond,
|
||||
/datum/material/uranium,
|
||||
/datum/material/plasma,
|
||||
/datum/material/bluespace,
|
||||
/datum/material/bananium,
|
||||
/datum/material/titanium,
|
||||
/datum/material/runite,
|
||||
/datum/material/plastic,
|
||||
/datum/material/adamantine,
|
||||
/datum/material/mythril,
|
||||
/datum/material/wood
|
||||
)
|
||||
var/list/allowed_materials
|
||||
|
||||
/// Base print speed
|
||||
var/base_print_speed = 10
|
||||
|
||||
/obj/machinery/autolathe/Initialize()
|
||||
AddComponent(/datum/component/material_container, allowed_materials, _show_on_examine=TRUE, _after_insert=CALLBACK(src, .proc/AfterMaterialInsert))
|
||||
var/list/mats = allowed_materials
|
||||
if(!mats)
|
||||
mats = SSmaterials.materialtypes_by_category[MAT_CATEGORY_RIGID]
|
||||
AddComponent(/datum/component/material_container, mats, _show_on_examine=TRUE, _after_insert=CALLBACK(src, .proc/AfterMaterialInsert))
|
||||
. = ..()
|
||||
wires = new /datum/wires/autolathe(src)
|
||||
stored_research = new stored_research
|
||||
|
||||
@@ -257,3 +257,12 @@
|
||||
name = "AI upload monitor"
|
||||
desc = "A telescreen that connects to the AI upload's camera network."
|
||||
network = list("aiupload")
|
||||
|
||||
// Subtype that connects to shuttles.
|
||||
/obj/machinery/computer/security/shuttle
|
||||
circuit = /obj/item/circuitboard/computer/security/shuttle
|
||||
|
||||
/obj/machinery/computer/security/shuttle/connect_to_shuttle(obj/docking_port/mobile/port, obj/docking_port/stationary/dock, idnum, override=FALSE)
|
||||
for(var/i in network)
|
||||
network -= i
|
||||
network += "[idnum][i]"
|
||||
|
||||
@@ -169,7 +169,8 @@
|
||||
|
||||
to_chat(user, "[src] is now in [mode] mode.")
|
||||
|
||||
/obj/item/grenade/barrier/prime()
|
||||
/obj/item/grenade/barrier/prime(mob/living/lanced_by)
|
||||
. = ..()
|
||||
new /obj/structure/barricade/security(get_turf(src.loc))
|
||||
switch(mode)
|
||||
if(VERTICAL)
|
||||
|
||||
@@ -413,8 +413,8 @@
|
||||
// shock user with probability prb (if all connections & power are working)
|
||||
// returns TRUE if shocked, FALSE otherwise
|
||||
// The preceding comment was borrowed from the grille's shock script
|
||||
/obj/machinery/door/airlock/proc/shock(mob/user, prb)
|
||||
if(!hasPower()) // unpowered, no shock
|
||||
/obj/machinery/door/airlock/proc/shock(mob/living/user, prb)
|
||||
if(!istype(user) || !hasPower()) // unpowered, no shock
|
||||
return FALSE
|
||||
if(shockCooldown > world.time)
|
||||
return FALSE //Already shocked someone recently?
|
||||
|
||||
@@ -12,12 +12,13 @@
|
||||
armor = list("melee" = 30, "bullet" = 30, "laser" = 20, "energy" = 20, "bomb" = 10, "bio" = 100, "rad" = 100, "fire" = 80, "acid" = 70)
|
||||
CanAtmosPass = ATMOS_PASS_DENSITY
|
||||
flags_1 = PREVENT_CLICK_UNDER_1
|
||||
ricochet_chance_mod = 0.8
|
||||
|
||||
interaction_flags_atom = INTERACT_ATOM_UI_INTERACT
|
||||
|
||||
var/secondsElectrified = 0
|
||||
var/shockedby
|
||||
var/visible = TRUE
|
||||
var/visible = TRUE // To explain: Whether the door can block line of sight when closed or not.
|
||||
var/operating = FALSE
|
||||
var/glass = FALSE
|
||||
var/welded = FALSE
|
||||
|
||||
@@ -54,6 +54,15 @@
|
||||
else
|
||||
icon_state = "[src.base_state]open"
|
||||
|
||||
/obj/machinery/door/window/update_atom_colour()
|
||||
if((color && (color_hex2num(color) < 255)))
|
||||
visible = TRUE
|
||||
if(density)
|
||||
set_opacity(TRUE)
|
||||
else
|
||||
visible = FALSE
|
||||
set_opacity(density && visible)
|
||||
|
||||
/obj/machinery/door/window/proc/open_and_close()
|
||||
open()
|
||||
if(src.check_access(null))
|
||||
@@ -143,16 +152,18 @@
|
||||
do_animate("opening")
|
||||
playsound(src.loc, 'sound/machines/windowdoor.ogg', 100, 1)
|
||||
src.icon_state ="[src.base_state]open"
|
||||
sleep(10)
|
||||
addtimer(CALLBACK(src, .proc/finish_opening), 10)
|
||||
return TRUE
|
||||
|
||||
/obj/machinery/door/window/proc/finish_opening()
|
||||
operating = FALSE
|
||||
density = FALSE
|
||||
// src.sd_set_opacity(0) //TODO: why is this here? Opaque windoors? ~Carn
|
||||
if(visible)
|
||||
set_opacity(FALSE)
|
||||
air_update_turf(1)
|
||||
update_freelook_sight()
|
||||
|
||||
if(operating == 1) //emag again
|
||||
operating = FALSE
|
||||
return 1
|
||||
|
||||
/obj/machinery/door/window/close(forced=0)
|
||||
if (src.operating)
|
||||
@@ -171,10 +182,13 @@
|
||||
density = TRUE
|
||||
air_update_turf(1)
|
||||
update_freelook_sight()
|
||||
sleep(10)
|
||||
addtimer(CALLBACK(src, .proc/finish_closing), 10)
|
||||
return TRUE
|
||||
|
||||
/obj/machinery/door/window/proc/finish_closing()
|
||||
if(visible)
|
||||
set_opacity(TRUE)
|
||||
operating = FALSE
|
||||
return 1
|
||||
|
||||
/obj/machinery/door/window/play_attack_sound(damage_amount, damage_type = BRUTE, damage_flag = 0)
|
||||
switch(damage_type)
|
||||
|
||||
@@ -13,7 +13,8 @@
|
||||
var/obj/item/reagent_containers/beaker
|
||||
var/static/list/drip_containers = typecacheof(list(/obj/item/reagent_containers/blood,
|
||||
/obj/item/reagent_containers/food,
|
||||
/obj/item/reagent_containers/glass))
|
||||
/obj/item/reagent_containers/glass,
|
||||
/obj/item/reagent_containers/chem_pack))
|
||||
|
||||
/obj/machinery/iv_drip/Initialize(mapload)
|
||||
. = ..()
|
||||
|
||||
@@ -0,0 +1,44 @@
|
||||
/obj/machinery/sheetifier
|
||||
name = "Sheet-meister 2000"
|
||||
desc = "A very sheety machine"
|
||||
icon = 'icons/obj/machines/sheetifier.dmi'
|
||||
icon_state = "base_machine"
|
||||
density = TRUE
|
||||
use_power = IDLE_POWER_USE
|
||||
idle_power_usage = 10
|
||||
active_power_usage = 100
|
||||
circuit = /obj/item/circuitboard/machine/sheetifier
|
||||
layer = BELOW_OBJ_LAYER
|
||||
var/busy_processing = FALSE
|
||||
|
||||
/obj/machinery/sheetifier/Initialize()
|
||||
. = ..()
|
||||
AddComponent(/datum/component/material_container, list(/datum/material/meat), MINERAL_MATERIAL_AMOUNT * MAX_STACK_SIZE * 2, TRUE, /obj/item/reagent_containers/food/snacks/meat/slab, CALLBACK(src, .proc/CanInsertMaterials), CALLBACK(src, .proc/AfterInsertMaterials))
|
||||
|
||||
/obj/machinery/sheetifier/update_overlays()
|
||||
. = ..()
|
||||
if(stat & (BROKEN|NOPOWER))
|
||||
return
|
||||
var/mutable_appearance/on_overlay = mutable_appearance(icon, "buttons_on")
|
||||
. += on_overlay
|
||||
|
||||
/obj/machinery/sheetifier/update_icon_state()
|
||||
icon_state = "base_machine[busy_processing ? "_processing" : ""]"
|
||||
|
||||
/obj/machinery/sheetifier/proc/CanInsertMaterials()
|
||||
return !busy_processing
|
||||
|
||||
/obj/machinery/sheetifier/proc/AfterInsertMaterials(item_inserted, id_inserted, amount_inserted)
|
||||
busy_processing = TRUE
|
||||
update_icon()
|
||||
var/datum/material/last_inserted_material = id_inserted
|
||||
var/mutable_appearance/processing_overlay = mutable_appearance(icon, "processing")
|
||||
processing_overlay.color = last_inserted_material.color
|
||||
flick_overlay_static(processing_overlay, src, 64)
|
||||
addtimer(CALLBACK(src, .proc/finish_processing), 64)
|
||||
|
||||
/obj/machinery/sheetifier/proc/finish_processing()
|
||||
busy_processing = FALSE
|
||||
update_icon()
|
||||
var/datum/component/material_container/materials = GetComponent(/datum/component/material_container)
|
||||
materials.retrieve_all() //Returns all as sheets
|
||||
@@ -0,0 +1,33 @@
|
||||
/obj/machinery/shuttle
|
||||
name = "shuttle component"
|
||||
desc = "Something for shuttles."
|
||||
density = TRUE
|
||||
obj_integrity = 250
|
||||
max_integrity = 250
|
||||
icon = 'icons/turf/shuttle.dmi'
|
||||
icon_state = "burst_plasma"
|
||||
idle_power_usage = 150
|
||||
circuit = /obj/item/circuitboard/machine/shuttle/engine
|
||||
var/icon_state_closed = "burst_plasma"
|
||||
var/icon_state_open = "burst_plasma_open"
|
||||
var/icon_state_off = "burst_plasma_off"
|
||||
|
||||
/obj/machinery/shuttle/Initialize()
|
||||
. = ..()
|
||||
GLOB.custom_shuttle_machines += src
|
||||
|
||||
/obj/machinery/shuttle/Destroy()
|
||||
. = ..()
|
||||
GLOB.custom_shuttle_machines -= src
|
||||
|
||||
/obj/machinery/shuttle/attackby(obj/item/I, mob/living/user, params)
|
||||
if(default_deconstruction_screwdriver(user, icon_state_open, icon_state_closed, I))
|
||||
return
|
||||
if(default_pry_open(I))
|
||||
return
|
||||
if(panel_open)
|
||||
if(default_change_direction_wrench(user, I))
|
||||
return
|
||||
if(default_deconstruction_crowbar(I))
|
||||
return
|
||||
return ..()
|
||||
@@ -0,0 +1,138 @@
|
||||
//-----------------------------------------------
|
||||
//-------------Engine Thrusters------------------
|
||||
//-----------------------------------------------
|
||||
|
||||
#define ENGINE_HEAT_TARGET 600
|
||||
#define ENGINE_HEATING_POWER 5000000
|
||||
|
||||
/obj/machinery/shuttle/engine
|
||||
name = "shuttle thruster"
|
||||
desc = "A thruster for shuttles."
|
||||
density = TRUE
|
||||
obj_integrity = 250
|
||||
max_integrity = 250
|
||||
icon = 'icons/turf/shuttle.dmi'
|
||||
icon_state = "burst_plasma"
|
||||
idle_power_usage = 150
|
||||
circuit = /obj/item/circuitboard/machine/shuttle/engine
|
||||
var/thrust = 0
|
||||
var/fuel_use = 0
|
||||
var/bluespace_capable = TRUE
|
||||
var/cooldown = 0
|
||||
var/thruster_active = FALSE
|
||||
var/datum/weakref/attached_heater
|
||||
|
||||
/obj/machinery/shuttle/engine/plasma
|
||||
name = "plasma thruster"
|
||||
desc = "A thruster that burns plasma stored in an adjacent plasma thruster heater."
|
||||
icon_state = "burst_plasma"
|
||||
icon_state_off = "burst_plasma_off"
|
||||
|
||||
idle_power_usage = 0
|
||||
circuit = /obj/item/circuitboard/machine/shuttle/engine/plasma
|
||||
thrust = 25
|
||||
fuel_use = 0.24
|
||||
bluespace_capable = FALSE
|
||||
cooldown = 45
|
||||
|
||||
/obj/machinery/shuttle/engine/void
|
||||
name = "void thruster"
|
||||
desc = "A thruster using technology to breach voidspace for propulsion."
|
||||
icon_state = "burst_void"
|
||||
icon_state_off = "burst_void"
|
||||
icon_state_closed = "burst_void"
|
||||
icon_state_open = "burst_void_open"
|
||||
idle_power_usage = 0
|
||||
circuit = /obj/item/circuitboard/machine/shuttle/engine/void
|
||||
thrust = 400
|
||||
fuel_use = 0
|
||||
bluespace_capable = TRUE
|
||||
cooldown = 90
|
||||
|
||||
/obj/machinery/shuttle/engine/Initialize()
|
||||
. = ..()
|
||||
check_setup()
|
||||
|
||||
/obj/machinery/shuttle/engine/on_construction()
|
||||
. = ..()
|
||||
check_setup()
|
||||
|
||||
/obj/machinery/shuttle/engine/Destroy()
|
||||
attached_heater = FALSE
|
||||
thruster_active = FALSE
|
||||
return ..()
|
||||
|
||||
/obj/machinery/shuttle/engine/proc/check_setup()
|
||||
if(!anchored)
|
||||
attached_heater = null
|
||||
update_engine()
|
||||
return
|
||||
var/heater_turf
|
||||
switch(dir)
|
||||
if(NORTH)
|
||||
heater_turf = get_offset_target_turf(src, 0, 1)
|
||||
if(SOUTH)
|
||||
heater_turf = get_offset_target_turf(src, 0, -1)
|
||||
if(EAST)
|
||||
heater_turf = get_offset_target_turf(src, 1, 0)
|
||||
if(WEST)
|
||||
heater_turf = get_offset_target_turf(src, -1, 0)
|
||||
if(!heater_turf)
|
||||
attached_heater = null
|
||||
update_engine()
|
||||
return
|
||||
attached_heater = null
|
||||
for(var/obj/machinery/atmospherics/components/unary/shuttle/heater/as_heater in heater_turf)
|
||||
if(as_heater.dir != dir)
|
||||
continue
|
||||
if(as_heater.panel_open)
|
||||
continue
|
||||
if(!as_heater.anchored)
|
||||
continue
|
||||
attached_heater = WEAKREF(as_heater)
|
||||
break
|
||||
update_engine()
|
||||
return
|
||||
|
||||
/obj/machinery/shuttle/engine/proc/update_engine()
|
||||
if(!attached_heater)
|
||||
icon_state = icon_state_off
|
||||
thruster_active = FALSE
|
||||
return
|
||||
var/obj/machinery/atmospherics/components/unary/shuttle/heater/resolved_heater = attached_heater.resolve()
|
||||
if(panel_open)
|
||||
thruster_active = FALSE
|
||||
else if(resolved_heater?.hasFuel(1))
|
||||
icon_state = icon_state_closed
|
||||
thruster_active = TRUE
|
||||
else
|
||||
thruster_active = FALSE
|
||||
icon_state = icon_state_off
|
||||
return
|
||||
|
||||
/obj/machinery/shuttle/engine/void/update_engine()
|
||||
if(panel_open)
|
||||
thruster_active = FALSE
|
||||
return
|
||||
thruster_active = TRUE
|
||||
icon_state = icon_state_closed
|
||||
return
|
||||
|
||||
//Thanks to spaceheater.dm for inspiration :)
|
||||
/obj/machinery/shuttle/engine/proc/fireEngine()
|
||||
var/turf/heatTurf = loc
|
||||
if(!heatTurf)
|
||||
return
|
||||
var/datum/gas_mixture/env = heatTurf.return_air()
|
||||
var/heat_cap = env.heat_capacity()
|
||||
var/req_power = abs(env.return_temperature() - ENGINE_HEAT_TARGET) * heat_cap
|
||||
req_power = min(req_power, ENGINE_HEATING_POWER)
|
||||
var/deltaTemperature = req_power / heat_cap
|
||||
if(deltaTemperature < 0)
|
||||
return
|
||||
env.temperature += deltaTemperature
|
||||
air_update_turf()
|
||||
|
||||
/obj/machinery/shuttle/engine/default_change_direction_wrench(mob/user, obj/item/I)
|
||||
. = ..()
|
||||
update_engine()
|
||||
@@ -0,0 +1,132 @@
|
||||
//-----------------------------------------------
|
||||
//--------------Engine Heaters-------------------
|
||||
//This uses atmospherics, much like a thermomachine,
|
||||
//but instead of changing temp, it stores plasma and uses
|
||||
//it for the engine.
|
||||
//-----------------------------------------------
|
||||
/obj/machinery/atmospherics/components/unary/shuttle
|
||||
name = "shuttle atmospherics device"
|
||||
desc = "This does something to do with shuttle atmospherics"
|
||||
icon_state = "heater"
|
||||
icon = 'icons/turf/shuttle.dmi'
|
||||
|
||||
/obj/machinery/atmospherics/components/unary/shuttle/heater
|
||||
name = "engine heater"
|
||||
desc = "Directs energy into compressed particles in order to power an attached thruster."
|
||||
icon_state = "heater_pipe"
|
||||
var/icon_state_closed = "heater_pipe"
|
||||
var/icon_state_open = "heater_pipe_open"
|
||||
var/icon_state_off = "heater_pipe"
|
||||
idle_power_usage = 50
|
||||
circuit = /obj/item/circuitboard/machine/shuttle/heater
|
||||
|
||||
density = TRUE
|
||||
max_integrity = 400
|
||||
armor = list("melee" = 0, "bullet" = 0, "laser" = 0, "energy" = 100, "bomb" = 0, "bio" = 100, "rad" = 100, "fire" = 100, "acid" = 30)
|
||||
layer = OBJ_LAYER
|
||||
showpipe = TRUE
|
||||
|
||||
pipe_flags = PIPING_ONE_PER_TURF | PIPING_DEFAULT_LAYER_ONLY
|
||||
|
||||
var/gas_type = /datum/gas/plasma
|
||||
var/efficiency_multiplier = 1
|
||||
var/gas_capacity = 0
|
||||
|
||||
/obj/machinery/atmospherics/components/unary/shuttle/heater/New()
|
||||
. = ..()
|
||||
GLOB.custom_shuttle_machines += src
|
||||
SetInitDirections()
|
||||
update_adjacent_engines()
|
||||
updateGasStats()
|
||||
|
||||
/obj/machinery/atmospherics/components/unary/shuttle/heater/Destroy()
|
||||
. = ..()
|
||||
update_adjacent_engines()
|
||||
GLOB.custom_shuttle_machines -= src
|
||||
|
||||
/obj/machinery/atmospherics/components/unary/shuttle/heater/on_construction()
|
||||
..(dir, dir)
|
||||
SetInitDirections()
|
||||
update_adjacent_engines()
|
||||
|
||||
/obj/machinery/atmospherics/components/unary/shuttle/heater/default_change_direction_wrench(mob/user, obj/item/I)
|
||||
if(!..())
|
||||
return FALSE
|
||||
SetInitDirections()
|
||||
var/obj/machinery/atmospherics/node = nodes[1]
|
||||
if(node)
|
||||
node.disconnect(src)
|
||||
nodes[1] = null
|
||||
if(!parents[1])
|
||||
return
|
||||
nullifyPipenet(parents[1])
|
||||
|
||||
atmosinit()
|
||||
node = nodes[1]
|
||||
if(node)
|
||||
node.atmosinit()
|
||||
node.addMember(src)
|
||||
build_network()
|
||||
return TRUE
|
||||
|
||||
/obj/machinery/atmospherics/components/unary/shuttle/heater/RefreshParts()
|
||||
var/cap = 0
|
||||
var/eff = 0
|
||||
for(var/obj/item/stock_parts/matter_bin/M in component_parts)
|
||||
cap += M.rating
|
||||
for(var/obj/item/stock_parts/micro_laser/L in component_parts)
|
||||
eff += L.rating
|
||||
gas_capacity = 5000 * ((cap - 1) ** 2) + 1000
|
||||
efficiency_multiplier = round(((eff / 2) / 2.8) ** 2, 0.1)
|
||||
updateGasStats()
|
||||
|
||||
/obj/machinery/atmospherics/components/unary/shuttle/heater/examine(mob/user)
|
||||
. = ..()
|
||||
var/datum/gas_mixture/air_contents = airs[1]
|
||||
. += "The engine heater's gas dial reads [air_contents.return_volume()] liters in internal tank.<br>"
|
||||
|
||||
/obj/machinery/atmospherics/components/unary/shuttle/heater/proc/updateGasStats()
|
||||
var/datum/gas_mixture/air_contents = airs[1]
|
||||
if(!air_contents)
|
||||
return
|
||||
air_contents.volume = gas_capacity
|
||||
air_contents.temperature = T20C
|
||||
|
||||
/obj/machinery/atmospherics/components/unary/shuttle/heater/proc/hasFuel(var/required)
|
||||
var/datum/gas_mixture/air_contents = airs[1]
|
||||
var/moles = air_contents.total_moles()
|
||||
return moles >= required
|
||||
|
||||
/obj/machinery/atmospherics/components/unary/shuttle/heater/proc/consumeFuel(var/amount)
|
||||
var/datum/gas_mixture/air_contents = airs[1]
|
||||
air_contents.remove(amount)
|
||||
return
|
||||
|
||||
/obj/machinery/atmospherics/components/unary/shuttle/heater/attackby(obj/item/I, mob/living/user, params)
|
||||
update_adjacent_engines()
|
||||
if(default_deconstruction_screwdriver(user, icon_state_open, icon_state_closed, I))
|
||||
return
|
||||
if(default_pry_open(I))
|
||||
return
|
||||
if(panel_open)
|
||||
if(default_change_direction_wrench(user, I))
|
||||
return
|
||||
if(default_deconstruction_crowbar(I))
|
||||
return
|
||||
return ..()
|
||||
|
||||
/obj/machinery/atmospherics/components/unary/shuttle/heater/proc/update_adjacent_engines()
|
||||
var/engine_turf
|
||||
switch(dir)
|
||||
if(NORTH)
|
||||
engine_turf = get_offset_target_turf(src, 0, -1)
|
||||
if(SOUTH)
|
||||
engine_turf = get_offset_target_turf(src, 0, 1)
|
||||
if(EAST)
|
||||
engine_turf = get_offset_target_turf(src, -1, 0)
|
||||
if(WEST)
|
||||
engine_turf = get_offset_target_turf(src, 1, 0)
|
||||
if(!engine_turf)
|
||||
return
|
||||
for(var/obj/machinery/shuttle/engine/E in engine_turf)
|
||||
E.check_setup()
|
||||
@@ -290,7 +290,7 @@
|
||||
if("shuttle_id")
|
||||
update()
|
||||
|
||||
/obj/machinery/status_display/shuttle/proc/connect_to_shuttle(obj/docking_port/mobile/port, obj/docking_port/stationary/dock, idnum, override)
|
||||
/obj/machinery/status_display/shuttle/connect_to_shuttle(obj/docking_port/mobile/port, obj/docking_port/stationary/dock, idnum, override)
|
||||
if (port && (shuttle_id == initial(shuttle_id) || override))
|
||||
shuttle_id = port.id
|
||||
update()
|
||||
|
||||
@@ -388,7 +388,7 @@
|
||||
/obj/item/mecha_parts/mecha_equipment/generator/get_equip_info()
|
||||
var/output = ..()
|
||||
if(output)
|
||||
return "[output] \[[fuel]: [round(fuel.amount*fuel.mats_per_stack,0.1)] cm<sup>3</sup>\] - <a href='?src=[REF(src)];toggle=1'>[equip_ready?"A":"Dea"]ctivate</a>"
|
||||
return "[output] \[[fuel]: [round(fuel.amount*MINERAL_MATERIAL_AMOUNT,0.1)] cm<sup>3</sup>\] - <a href='?src=[REF(src)];toggle=1'>[equip_ready?"A":"Dea"]ctivate</a>"
|
||||
|
||||
/obj/item/mecha_parts/mecha_equipment/generator/action(target)
|
||||
if(chassis)
|
||||
@@ -398,9 +398,9 @@
|
||||
|
||||
/obj/item/mecha_parts/mecha_equipment/generator/proc/load_fuel(var/obj/item/stack/sheet/P)
|
||||
if(P.type == fuel.type && P.amount > 0)
|
||||
var/to_load = max(max_fuel - fuel.amount*fuel.mats_per_stack,0)
|
||||
var/to_load = max(max_fuel - fuel.amount*MINERAL_MATERIAL_AMOUNT,0)
|
||||
if(to_load)
|
||||
var/units = min(max(round(to_load / P.mats_per_stack),1),P.amount)
|
||||
var/units = min(max(round(to_load / MINERAL_MATERIAL_AMOUNT),1),P.amount)
|
||||
fuel.amount += units
|
||||
P.use(units)
|
||||
occupant_message("[units] unit\s of [fuel] successfully loaded.")
|
||||
@@ -454,7 +454,7 @@
|
||||
if(cur_charge < chassis.cell.maxcharge)
|
||||
use_fuel = fuel_per_cycle_active
|
||||
chassis.give_power(power_per_cycle)
|
||||
fuel.amount -= min(use_fuel/fuel.mats_per_stack,fuel.amount)
|
||||
fuel.amount -= min(use_fuel/MINERAL_MATERIAL_AMOUNT,fuel.amount)
|
||||
update_equip_info()
|
||||
return 1
|
||||
|
||||
|
||||
@@ -26,6 +26,7 @@
|
||||
"Firefighter",
|
||||
"Odysseus",
|
||||
"Gygax",
|
||||
"Medical-Spec Gygax",
|
||||
"Durand",
|
||||
"H.O.N.K",
|
||||
"Phazon",
|
||||
|
||||
@@ -642,6 +642,304 @@
|
||||
user.visible_message("[user] unfastens Gygax Armor Plates.", "<span class='notice'>You unfasten Gygax Armor Plates.</span>")
|
||||
return TRUE
|
||||
|
||||
//Begin Medigax
|
||||
/datum/component/construction/unordered/mecha_chassis/medigax
|
||||
result = /datum/component/construction/mecha/medigax
|
||||
steps = list(
|
||||
/obj/item/mecha_parts/part/medigax_torso,
|
||||
/obj/item/mecha_parts/part/medigax_left_arm,
|
||||
/obj/item/mecha_parts/part/medigax_right_arm,
|
||||
/obj/item/mecha_parts/part/medigax_left_leg,
|
||||
/obj/item/mecha_parts/part/medigax_right_leg,
|
||||
/obj/item/mecha_parts/part/medigax_head
|
||||
)
|
||||
|
||||
/datum/component/construction/mecha/medigax
|
||||
result = /obj/mecha/medical/medigax
|
||||
base_icon = "medigax"
|
||||
steps = list(
|
||||
//1
|
||||
list(
|
||||
"key" = TOOL_WRENCH,
|
||||
"desc" = "The hydraulic systems are disconnected."
|
||||
),
|
||||
|
||||
//2
|
||||
list(
|
||||
"key" = TOOL_SCREWDRIVER,
|
||||
"back_key" = TOOL_WRENCH,
|
||||
"desc" = "The hydraulic systems are connected."
|
||||
),
|
||||
|
||||
//3
|
||||
list(
|
||||
"key" = /obj/item/stack/cable_coil,
|
||||
"amount" = 5,
|
||||
"back_key" = TOOL_SCREWDRIVER,
|
||||
"desc" = "The hydraulic systems are active."
|
||||
),
|
||||
|
||||
//4
|
||||
list(
|
||||
"key" = TOOL_WIRECUTTER,
|
||||
"back_key" = TOOL_SCREWDRIVER,
|
||||
"desc" = "The wiring is added."
|
||||
),
|
||||
|
||||
//5
|
||||
list(
|
||||
"key" = /obj/item/circuitboard/mecha/gygax/main,
|
||||
"action" = ITEM_DELETE,
|
||||
"back_key" = TOOL_SCREWDRIVER,
|
||||
"desc" = "The wiring is adjusted."
|
||||
),
|
||||
|
||||
//6
|
||||
list(
|
||||
"key" = TOOL_SCREWDRIVER,
|
||||
"back_key" = TOOL_CROWBAR,
|
||||
"desc" = "Central control module is installed."
|
||||
),
|
||||
|
||||
//7
|
||||
list(
|
||||
"key" = /obj/item/circuitboard/mecha/gygax/peripherals,
|
||||
"action" = ITEM_DELETE,
|
||||
"back_key" = TOOL_SCREWDRIVER,
|
||||
"desc" = "Central control module is secured."
|
||||
),
|
||||
|
||||
//8
|
||||
list(
|
||||
"key" = TOOL_SCREWDRIVER,
|
||||
"back_key" = TOOL_CROWBAR,
|
||||
"desc" = "Peripherals control module is installed."
|
||||
),
|
||||
|
||||
//9
|
||||
list(
|
||||
"key" = /obj/item/circuitboard/mecha/gygax/targeting,
|
||||
"action" = ITEM_DELETE,
|
||||
"back_key" = TOOL_SCREWDRIVER,
|
||||
"desc" = "Peripherals control module is secured."
|
||||
),
|
||||
|
||||
//10
|
||||
list(
|
||||
"key" = TOOL_SCREWDRIVER,
|
||||
"back_key" = TOOL_CROWBAR,
|
||||
"desc" = "Weapon control module is installed."
|
||||
),
|
||||
|
||||
//11
|
||||
list(
|
||||
"key" = /obj/item/stock_parts/scanning_module,
|
||||
"action" = ITEM_MOVE_INSIDE,
|
||||
"back_key" = TOOL_SCREWDRIVER,
|
||||
"desc" = "Weapon control module is secured."
|
||||
),
|
||||
|
||||
//12
|
||||
list(
|
||||
"key" = TOOL_SCREWDRIVER,
|
||||
"back_key" = TOOL_CROWBAR,
|
||||
"desc" = "Scanner module is installed."
|
||||
),
|
||||
|
||||
//13
|
||||
list(
|
||||
"key" = /obj/item/stock_parts/capacitor,
|
||||
"action" = ITEM_MOVE_INSIDE,
|
||||
"back_key" = TOOL_SCREWDRIVER,
|
||||
"desc" = "Scanner module is secured."
|
||||
),
|
||||
|
||||
//14
|
||||
list(
|
||||
"key" = TOOL_SCREWDRIVER,
|
||||
"back_key" = TOOL_CROWBAR,
|
||||
"desc" = "Capacitor is installed."
|
||||
),
|
||||
|
||||
//15
|
||||
list(
|
||||
"key" = /obj/item/stock_parts/cell,
|
||||
"action" = ITEM_MOVE_INSIDE,
|
||||
"back_key" = TOOL_SCREWDRIVER,
|
||||
"desc" = "Capacitor is secured."
|
||||
),
|
||||
|
||||
//16
|
||||
list(
|
||||
"key" = TOOL_SCREWDRIVER,
|
||||
"back_key" = TOOL_CROWBAR,
|
||||
"desc" = "The power cell is installed."
|
||||
),
|
||||
|
||||
//17
|
||||
list(
|
||||
"key" = /obj/item/stack/sheet/metal,
|
||||
"amount" = 5,
|
||||
"back_key" = TOOL_SCREWDRIVER,
|
||||
"desc" = "The power cell is secured."
|
||||
),
|
||||
|
||||
//18
|
||||
list(
|
||||
"key" = TOOL_WRENCH,
|
||||
"back_key" = TOOL_CROWBAR,
|
||||
"desc" = "Internal armor is installed."
|
||||
),
|
||||
|
||||
//19
|
||||
list(
|
||||
"key" = TOOL_WELDER,
|
||||
"back_key" = TOOL_WRENCH,
|
||||
"desc" = "Internal armor is wrenched."
|
||||
),
|
||||
|
||||
//20
|
||||
list(
|
||||
"key" = /obj/item/mecha_parts/part/medigax_armor,
|
||||
"action" = ITEM_DELETE,
|
||||
"back_key" = TOOL_WELDER,
|
||||
"desc" = "Internal armor is welded."
|
||||
),
|
||||
|
||||
//21
|
||||
list(
|
||||
"key" = TOOL_WRENCH,
|
||||
"back_key" = TOOL_CROWBAR,
|
||||
"desc" = "External armor is installed."
|
||||
),
|
||||
|
||||
//22
|
||||
list(
|
||||
"key" = TOOL_WELDER,
|
||||
"back_key" = TOOL_WRENCH,
|
||||
"desc" = "External armor is wrenched."
|
||||
),
|
||||
|
||||
)
|
||||
|
||||
/datum/component/construction/mecha/medigax/action(datum/source, atom/used_atom, mob/user)
|
||||
return check_step(used_atom,user)
|
||||
|
||||
/datum/component/construction/mecha/medigax/custom_action(obj/item/I, mob/living/user, diff)
|
||||
if(!..())
|
||||
return FALSE
|
||||
|
||||
switch(index)
|
||||
if(1)
|
||||
user.visible_message("[user] connects [parent] hydraulic systems", "<span class='notice'>You connect [parent] hydraulic systems.</span>")
|
||||
if(2)
|
||||
if(diff==FORWARD)
|
||||
user.visible_message("[user] activates [parent] hydraulic systems.", "<span class='notice'>You activate [parent] hydraulic systems.</span>")
|
||||
else
|
||||
user.visible_message("[user] disconnects [parent] hydraulic systems", "<span class='notice'>You disconnect [parent] hydraulic systems.</span>")
|
||||
if(3)
|
||||
if(diff==FORWARD)
|
||||
user.visible_message("[user] adds the wiring to [parent].", "<span class='notice'>You add the wiring to [parent].</span>")
|
||||
else
|
||||
user.visible_message("[user] deactivates [parent] hydraulic systems.", "<span class='notice'>You deactivate [parent] hydraulic systems.</span>")
|
||||
if(4)
|
||||
if(diff==FORWARD)
|
||||
user.visible_message("[user] adjusts the wiring of [parent].", "<span class='notice'>You adjust the wiring of [parent].</span>")
|
||||
else
|
||||
user.visible_message("[user] removes the wiring from [parent].", "<span class='notice'>You remove the wiring from [parent].</span>")
|
||||
if(5)
|
||||
if(diff==FORWARD)
|
||||
user.visible_message("[user] installs [I] into [parent].", "<span class='notice'>You install [I] into [parent].</span>")
|
||||
else
|
||||
user.visible_message("[user] disconnects the wiring of [parent].", "<span class='notice'>You disconnect the wiring of [parent].</span>")
|
||||
if(6)
|
||||
if(diff==FORWARD)
|
||||
user.visible_message("[user] secures the mainboard.", "<span class='notice'>You secure the mainboard.</span>")
|
||||
else
|
||||
user.visible_message("[user] removes the central control module from [parent].", "<span class='notice'>You remove the central computer mainboard from [parent].</span>")
|
||||
if(7)
|
||||
if(diff==FORWARD)
|
||||
user.visible_message("[user] installs [I] into [parent].", "<span class='notice'>You install [I] into [parent].</span>")
|
||||
else
|
||||
user.visible_message("[user] unfastens the mainboard.", "<span class='notice'>You unfasten the mainboard.</span>")
|
||||
if(8)
|
||||
if(diff==FORWARD)
|
||||
user.visible_message("[user] secures the peripherals control module.", "<span class='notice'>You secure the peripherals control module.</span>")
|
||||
else
|
||||
user.visible_message("[user] removes the peripherals control module from [parent].", "<span class='notice'>You remove the peripherals control module from [parent].</span>")
|
||||
if(9)
|
||||
if(diff==FORWARD)
|
||||
user.visible_message("[user] installs [I] into [parent].", "<span class='notice'>You install [I] into [parent].</span>")
|
||||
else
|
||||
user.visible_message("[user] unfastens the peripherals control module.", "<span class='notice'>You unfasten the peripherals control module.</span>")
|
||||
if(10)
|
||||
if(diff==FORWARD)
|
||||
user.visible_message("[user] secures the weapon control module.", "<span class='notice'>You secure the weapon control module.</span>")
|
||||
else
|
||||
user.visible_message("[user] removes the weapon control module from [parent].", "<span class='notice'>You remove the weapon control module from [parent].</span>")
|
||||
if(11)
|
||||
if(diff==FORWARD)
|
||||
user.visible_message("[user] installs [I] to [parent].", "<span class='notice'>You install [I] to [parent].</span>")
|
||||
else
|
||||
user.visible_message("[user] unfastens the weapon control module.", "<span class='notice'>You unfasten the weapon control module.</span>")
|
||||
if(12)
|
||||
if(diff==FORWARD)
|
||||
user.visible_message("[user] secures the scanner module.", "<span class='notice'>You secure the scanner module.</span>")
|
||||
else
|
||||
user.visible_message("[user] removes the scanner module from [parent].", "<span class='notice'>You remove the scanner module from [parent].</span>")
|
||||
if(13)
|
||||
if(diff==FORWARD)
|
||||
user.visible_message("[user] installs [I] to [parent].", "<span class='notice'>You install [I] to [parent].</span>")
|
||||
else
|
||||
user.visible_message("[user] unfastens the scanner module.", "<span class='notice'>You unfasten the scanner module.</span>")
|
||||
if(14)
|
||||
if(diff==FORWARD)
|
||||
user.visible_message("[user] secures the capacitor.", "<span class='notice'>You secure the capacitor.</span>")
|
||||
else
|
||||
user.visible_message("[user] removes the capacitor from [parent].", "<span class='notice'>You remove the capacitor from [parent].</span>")
|
||||
if(15)
|
||||
if(diff==FORWARD)
|
||||
user.visible_message("[user] installs [I] into [parent].", "<span class='notice'>You install [I] into [parent].</span>")
|
||||
else
|
||||
user.visible_message("[user] unfastens the capacitor.", "<span class='notice'>You unfasten the capacitor.</span>")
|
||||
if(16)
|
||||
if(diff==FORWARD)
|
||||
user.visible_message("[user] secures the power cell.", "<span class='notice'>You secure the power cell.</span>")
|
||||
else
|
||||
user.visible_message("[user] pries the power cell from [parent].", "<span class='notice'>You pry the power cell from [parent].</span>")
|
||||
if(17)
|
||||
if(diff==FORWARD)
|
||||
user.visible_message("[user] installs the internal armor layer to [parent].", "<span class='notice'>You install the internal armor layer to [parent].</span>")
|
||||
else
|
||||
user.visible_message("[user] unfastens the power cell.", "<span class='notice'>You unfasten the power cell.</span>")
|
||||
if(18)
|
||||
if(diff==FORWARD)
|
||||
user.visible_message("[user] secures the internal armor layer.", "<span class='notice'>You secure the internal armor layer.</span>")
|
||||
else
|
||||
user.visible_message("[user] pries internal armor layer from [parent].", "<span class='notice'>You pry internal armor layer from [parent].</span>")
|
||||
if(19)
|
||||
if(diff==FORWARD)
|
||||
user.visible_message("[user] welds the internal armor layer to [parent].", "<span class='notice'>You weld the internal armor layer to [parent].</span>")
|
||||
else
|
||||
user.visible_message("[user] unfastens the internal armor layer.", "<span class='notice'>You unfasten the internal armor layer.</span>")
|
||||
if(20)
|
||||
if(diff==FORWARD)
|
||||
user.visible_message("[user] installs [I] to [parent].", "<span class='notice'>You install [I] to [parent].</span>")
|
||||
else
|
||||
user.visible_message("[user] cuts the internal armor layer from [parent].", "<span class='notice'>You cut the internal armor layer from [parent].</span>")
|
||||
if(21)
|
||||
if(diff==FORWARD)
|
||||
user.visible_message("[user] secures Gygax Armor Plates.", "<span class='notice'>You secure Medical Gygax Armor Plates.</span>")
|
||||
else
|
||||
user.visible_message("[user] pries Gygax Armor Plates from [parent].", "<span class='notice'>You pry Medical Gygax Armor Plates from [parent].</span>")
|
||||
if(22)
|
||||
if(diff==FORWARD)
|
||||
user.visible_message("[user] welds Gygax Armor Plates to [parent].", "<span class='notice'>You weld Medical Gygax Armor Plates to [parent].</span>")
|
||||
else
|
||||
user.visible_message("[user] unfastens Gygax Armor Plates.", "<span class='notice'>You unfasten Medical Gygax Armor Plates.</span>")
|
||||
return TRUE
|
||||
// End Medigax
|
||||
|
||||
/datum/component/construction/unordered/mecha_chassis/firefighter
|
||||
result = /datum/component/construction/mecha/firefighter
|
||||
steps = list(
|
||||
|
||||
@@ -129,6 +129,47 @@
|
||||
desc = "A set of armor plates designed for the Gygax. Designed to effectively deflect damage with a lightweight construction."
|
||||
icon_state = "gygax_armor"
|
||||
|
||||
///////// Medical Gygax
|
||||
|
||||
/obj/item/mecha_parts/chassis/medigax
|
||||
name = "\improper Medical Gygax chassis"
|
||||
construct_type = /datum/component/construction/unordered/mecha_chassis/medigax
|
||||
|
||||
/obj/item/mecha_parts/part/medigax_torso
|
||||
name = "\improper Medical Gygax torso"
|
||||
desc = "A torso part of Gygax. Contains power unit, processing core and life support systems."
|
||||
icon_state = "medigax_harness"
|
||||
|
||||
/obj/item/mecha_parts/part/medigax_head
|
||||
name = "\improper Medical Gygax head"
|
||||
desc = "A Gygax head. Houses advanced surveillance and targeting sensors."
|
||||
icon_state = "medigax_head"
|
||||
|
||||
/obj/item/mecha_parts/part/medigax_left_arm
|
||||
name = "\improper Medical Gygax left arm"
|
||||
desc = "A Gygax left arm. Data and power sockets are compatible with most exosuit tools and weapons."
|
||||
icon_state = "medigax_l_arm"
|
||||
|
||||
/obj/item/mecha_parts/part/medigax_right_arm
|
||||
name = "\improper Medical Gygax right arm"
|
||||
desc = "A Gygax right arm. Data and power sockets are compatible with most exosuit tools and weapons."
|
||||
icon_state = "medigax_r_arm"
|
||||
|
||||
/obj/item/mecha_parts/part/medigax_left_leg
|
||||
name = "\improper Medical Gygax left leg"
|
||||
desc = "A Gygax left leg. Constructed with advanced servomechanisms and actuators to enable faster speed."
|
||||
icon_state = "medigax_l_leg"
|
||||
|
||||
/obj/item/mecha_parts/part/medigax_right_leg
|
||||
name = "\improper Medical Gygax right leg"
|
||||
desc = "A Gygax right leg. Constructed with advanced servomechanisms and actuators to enable faster speed."
|
||||
icon_state = "medigax_r_leg"
|
||||
|
||||
/obj/item/mecha_parts/part/medigax_armor
|
||||
gender = PLURAL
|
||||
name = "\improper Medical Gygax armor plates"
|
||||
desc = "A set of armor plates designed for the Gygax. Designed to effectively deflect damage with a lightweight construction."
|
||||
icon_state = "medigax_armor"
|
||||
|
||||
//////////// Durand
|
||||
|
||||
|
||||
@@ -125,6 +125,24 @@
|
||||
name = "\improper Dark Gygax wreckage"
|
||||
icon_state = "darkgygax-broken"
|
||||
|
||||
/obj/structure/mecha_wreckage/medigax
|
||||
name = "\improper Medical Gygax wreckage"
|
||||
icon_state = "medigax-broken"
|
||||
|
||||
/obj/structure/mecha_wreckage/medigax/Initialize()
|
||||
. = ..()
|
||||
var/list/parts = list(/obj/item/mecha_parts/part/medigax_torso,
|
||||
/obj/item/mecha_parts/part/medigax_head,
|
||||
/obj/item/mecha_parts/part/medigax_left_arm,
|
||||
/obj/item/mecha_parts/part/medigax_right_arm,
|
||||
/obj/item/mecha_parts/part/medigax_left_leg,
|
||||
/obj/item/mecha_parts/part/medigax_right_leg)
|
||||
for(var/i = 0; i < 2; i++)
|
||||
if(parts.len && prob(40))
|
||||
var/part = pick(parts)
|
||||
welder_salvage += part
|
||||
parts -= part
|
||||
|
||||
/obj/structure/mecha_wreckage/marauder
|
||||
name = "\improper Marauder wreckage"
|
||||
icon_state = "marauder-broken"
|
||||
|
||||
@@ -0,0 +1,34 @@
|
||||
/obj/mecha/medical/medigax
|
||||
desc = "A Gygax with it's actuator overload stripped and a slick white paint scheme, for medical use, These exosuits are developed and produced by Vey-Med. (© All rights reserved)."
|
||||
name = "\improper Medical Gygax"
|
||||
icon_state = "medigax"
|
||||
step_in = 1.75 // a little faster than an odysseus
|
||||
max_temperature = 25000
|
||||
max_integrity = 250
|
||||
wreckage = /obj/structure/mecha_wreckage/odysseus
|
||||
armor = list("melee" = 25, "bullet" = 20, "laser" = 30, "energy" = 15, "bomb" = 0, "bio" = 0, "rad" = 0, "fire" = 100, "acid" = 100)
|
||||
internal_damage_threshold = 35
|
||||
deflect_chance = 15
|
||||
step_energy_drain = 6
|
||||
infra_luminosity = 6
|
||||
|
||||
|
||||
/obj/mecha/medical/medigax/moved_inside(mob/living/carbon/human/H)
|
||||
. = ..()
|
||||
if(.)
|
||||
var/datum/atom_hud/hud = GLOB.huds[DATA_HUD_MEDICAL_ADVANCED]
|
||||
hud.add_hud_to(H)
|
||||
|
||||
/obj/mecha/medical/medigax/go_out()
|
||||
if(isliving(occupant))
|
||||
var/mob/living/carbon/human/L = occupant
|
||||
var/datum/atom_hud/hud = GLOB.huds[DATA_HUD_MEDICAL_ADVANCED]
|
||||
hud.remove_hud_from(L)
|
||||
..()
|
||||
|
||||
/obj/mecha/medical/medigax/mmi_moved_inside(obj/item/mmi/mmi_as_oc, mob/user)
|
||||
. = ..()
|
||||
if(.)
|
||||
var/datum/atom_hud/hud = GLOB.huds[DATA_HUD_MEDICAL_ADVANCED]
|
||||
var/mob/living/brain/B = mmi_as_oc.brainmob
|
||||
hud.add_hud_to(B)
|
||||
@@ -428,6 +428,11 @@
|
||||
desc = "A poster decipting a snake shaped into an ominous 'S'!"
|
||||
icon_state = "poster47"
|
||||
|
||||
/obj/structure/sign/poster/contraband/bountyhunters
|
||||
name = "Bounty Hunters"
|
||||
desc = "A poster advertising bounty hunting services. \"I hear you got a problem.\""
|
||||
icon_state = "poster48"
|
||||
|
||||
/obj/structure/sign/poster/official
|
||||
poster_item_name = "motivational poster"
|
||||
poster_item_desc = "An official Nanotrasen-issued poster to foster a compliant and obedient workforce. It comes with state-of-the-art adhesive backing, for easy pinning to any vertical surface."
|
||||
|
||||
@@ -91,7 +91,7 @@
|
||||
var/mob/living/carbon/human/H = O
|
||||
var/obj/item/clothing/shoes/S = H.shoes
|
||||
if(S && S.bloody_shoes[blood_state])
|
||||
if(color != bloodtype_to_color(S.last_bloodtype))
|
||||
if(color != S.last_blood_color)
|
||||
return
|
||||
S.bloody_shoes[blood_state] = max(S.bloody_shoes[blood_state] - BLOOD_LOSS_PER_STEP, 0)
|
||||
shoe_types |= S.type
|
||||
@@ -104,7 +104,7 @@
|
||||
var/mob/living/carbon/human/H = O
|
||||
var/obj/item/clothing/shoes/S = H.shoes
|
||||
if(S && S.bloody_shoes[blood_state])
|
||||
if(color != bloodtype_to_color(S.last_bloodtype))//last entry - we check its color
|
||||
if(color != S.last_blood_color)//last entry - we check its color
|
||||
return
|
||||
S.bloody_shoes[blood_state] = max(S.bloody_shoes[blood_state] - BLOOD_LOSS_PER_STEP, 0)
|
||||
shoe_types |= S.type
|
||||
|
||||
@@ -5,19 +5,21 @@
|
||||
anchored = TRUE
|
||||
icon = 'icons/obj/items_and_weapons.dmi'
|
||||
icon_state = "uglymine"
|
||||
var/triggered = 0
|
||||
/// We manually check to see if we've been triggered in case multiple atoms cross us in the time between the mine being triggered and it actually deleting, to avoid a race condition with multiple detonations
|
||||
var/triggered = FALSE
|
||||
|
||||
/obj/effect/mine/proc/mineEffect(mob/victim)
|
||||
to_chat(victim, "<span class='danger'>*click*</span>")
|
||||
|
||||
/obj/effect/mine/Crossed(AM as mob|obj)
|
||||
if(isturf(loc))
|
||||
if(ismob(AM))
|
||||
var/mob/MM = AM
|
||||
if(!(MM.movement_type & FLYING))
|
||||
triggermine(AM)
|
||||
else
|
||||
triggermine(AM)
|
||||
/obj/effect/mine/Crossed(atom/movable/AM)
|
||||
if(triggered || !isturf(loc))
|
||||
return
|
||||
. = ..()
|
||||
|
||||
if(AM.movement_type & FLYING)
|
||||
return
|
||||
|
||||
triggermine(AM)
|
||||
|
||||
/obj/effect/mine/proc/triggermine(mob/victim)
|
||||
if(triggered)
|
||||
@@ -27,9 +29,13 @@
|
||||
s.set_up(3, 1, src)
|
||||
s.start()
|
||||
mineEffect(victim)
|
||||
SEND_SIGNAL(src, COMSIG_MINE_TRIGGERED)
|
||||
triggered = 1
|
||||
qdel(src)
|
||||
|
||||
/obj/effect/mine/take_damage(damage_amount, damage_type, damage_flag, sound_effect, attack_dir)
|
||||
. = ..()
|
||||
triggermine()
|
||||
|
||||
/obj/effect/mine/explosive
|
||||
name = "explosive mine"
|
||||
@@ -50,6 +56,18 @@
|
||||
if(isliving(victim))
|
||||
victim.DefaultCombatKnockdown(stun_time)
|
||||
|
||||
/obj/effect/mine/shrapnel
|
||||
name = "shrapnel mine"
|
||||
var/shrapnel_type = /obj/item/projectile/bullet/shrapnel
|
||||
var/shrapnel_magnitude = 3
|
||||
|
||||
/obj/effect/mine/shrapnel/mineEffect(mob/victim)
|
||||
AddComponent(/datum/component/pellet_cloud, projectile_type=shrapnel_type, magnitude=shrapnel_magnitude)
|
||||
|
||||
/obj/effect/mine/shrapnel/sting
|
||||
name = "stinger mine"
|
||||
shrapnel_type = /obj/item/projectile/bullet/pellet/stingball
|
||||
|
||||
/obj/effect/mine/kickmine
|
||||
name = "kick mine"
|
||||
|
||||
@@ -105,7 +123,7 @@
|
||||
/obj/effect/mine/pickup/triggermine(mob/victim)
|
||||
if(triggered)
|
||||
return
|
||||
triggered = 1
|
||||
triggered = TRUE
|
||||
invisibility = INVISIBILITY_ABSTRACT
|
||||
mineEffect(victim)
|
||||
qdel(src)
|
||||
|
||||
@@ -491,7 +491,7 @@
|
||||
/obj/item/kitchen/knife = 5,
|
||||
/obj/item/screwdriver = 5,
|
||||
/obj/item/crowbar/red = 1, //Dont you need a crowbar to open this?
|
||||
/obj/item/stack/medical/bruise_pack = 3,
|
||||
/obj/item/stack/medical/suture = 3,
|
||||
/obj/item/reagent_containers/food/drinks/bottle/vodka = 2,
|
||||
/obj/item/radio = 5,
|
||||
/obj/item/flashlight = 4,
|
||||
|
||||
+175
-18
@@ -4,6 +4,9 @@ GLOBAL_VAR_INIT(rpg_loot_items, FALSE)
|
||||
// if true, everyone item when created will have its name changed to be
|
||||
// more... RPG-like.
|
||||
|
||||
GLOBAL_VAR_INIT(stickpocalypse, FALSE) // if true, all non-embeddable items will be able to harmlessly stick to people when thrown
|
||||
GLOBAL_VAR_INIT(embedpocalypse, FALSE) // if true, all items will be able to embed in people, takes precedence over stickpocalypse
|
||||
|
||||
/obj/item
|
||||
name = "item"
|
||||
icon = 'icons/obj/items_and_weapons.dmi'
|
||||
@@ -104,7 +107,7 @@ GLOBAL_VAR_INIT(rpg_loot_items, FALSE)
|
||||
|
||||
mouse_drag_pointer = MOUSE_ACTIVE_POINTER //the icon to indicate this object is being dragged
|
||||
|
||||
var/datum/embedding_behavior/embedding
|
||||
var/list/embedding = NONE
|
||||
|
||||
var/flags_cover = 0 //for flags such as GLASSESCOVERSEYES
|
||||
var/heat = 0
|
||||
@@ -159,7 +162,7 @@ GLOBAL_VAR_INIT(rpg_loot_items, FALSE)
|
||||
|
||||
/obj/item/Initialize()
|
||||
|
||||
if (attack_verb)
|
||||
if(attack_verb)
|
||||
attack_verb = typelist("attack_verb", attack_verb)
|
||||
|
||||
. = ..()
|
||||
@@ -167,9 +170,6 @@ GLOBAL_VAR_INIT(rpg_loot_items, FALSE)
|
||||
new path(src)
|
||||
actions_types = null
|
||||
|
||||
if(GLOB.rpg_loot_items)
|
||||
AddComponent(/datum/component/fantasy)
|
||||
|
||||
if(force_string)
|
||||
item_flags |= FORCE_STRING_OVERRIDE
|
||||
|
||||
@@ -179,16 +179,6 @@ GLOBAL_VAR_INIT(rpg_loot_items, FALSE)
|
||||
if(damtype == "brute")
|
||||
hitsound = "swing_hit"
|
||||
|
||||
if (!embedding)
|
||||
embedding = getEmbeddingBehavior()
|
||||
else if (islist(embedding))
|
||||
embedding = getEmbeddingBehavior(arglist(embedding))
|
||||
else if (!istype(embedding, /datum/embedding_behavior))
|
||||
stack_trace("Invalid type [embedding.type] found in .embedding during /obj/item Initialize()")
|
||||
|
||||
if(sharpness) //give sharp objects butchering functionality, for consistency
|
||||
AddComponent(/datum/component/butchering, 80 * toolspeed)
|
||||
|
||||
/obj/item/Destroy()
|
||||
item_flags &= ~DROPDEL //prevent reqdels
|
||||
if(ismob(loc))
|
||||
@@ -198,6 +188,26 @@ GLOBAL_VAR_INIT(rpg_loot_items, FALSE)
|
||||
qdel(X)
|
||||
return ..()
|
||||
|
||||
/obj/item/ComponentInitialize()
|
||||
. = ..()
|
||||
|
||||
// this proc says it's for initializing components, but we're initializing elements too because it's you and me against the world >:)
|
||||
if(!LAZYLEN(embedding))
|
||||
if(GLOB.embedpocalypse)
|
||||
embedding = EMBED_POINTY
|
||||
name = "pointy [name]"
|
||||
else if(GLOB.stickpocalypse)
|
||||
embedding = EMBED_HARMLESS
|
||||
name = "sticky [name]"
|
||||
|
||||
updateEmbedding()
|
||||
|
||||
if(GLOB.rpg_loot_items)
|
||||
AddComponent(/datum/component/fantasy)
|
||||
|
||||
if(sharpness) //give sharp objects butchering functionality, for consistency
|
||||
AddComponent(/datum/component/butchering, 80 * toolspeed)
|
||||
|
||||
/obj/item/proc/check_allowed_items(atom/target, not_inside, target_self)
|
||||
if(((src in target) && !target_self) || (!isturf(target.loc) && !isturf(target) && not_inside))
|
||||
return 0
|
||||
@@ -247,7 +257,7 @@ GLOBAL_VAR_INIT(rpg_loot_items, FALSE)
|
||||
. += "[src] is made of cold-resistant materials."
|
||||
if(resistance_flags & FIRE_PROOF)
|
||||
. += "[src] is made of fire-retardant materials."
|
||||
|
||||
|
||||
if(item_flags & (ITEM_CAN_BLOCK | ITEM_CAN_PARRY))
|
||||
var/datum/block_parry_data/data = return_block_parry_datum(block_parry_data)
|
||||
. += "[src] has the capacity to be used to block and/or parry. <a href='?src=[REF(data)];name=[name];block=[item_flags & ITEM_CAN_BLOCK];parry=[item_flags & ITEM_CAN_PARRY];render=1'>\[Show Stats\]</a>"
|
||||
@@ -625,6 +635,18 @@ GLOBAL_VAR_INIT(rpg_loot_items, FALSE)
|
||||
var/itempush = 1
|
||||
if(w_class < 4)
|
||||
itempush = 0 //too light to push anything
|
||||
if(isliving(hit_atom)) //Living mobs handle hit sounds differently.
|
||||
var/volume = get_volume_by_throwforce_and_or_w_class()
|
||||
if (throwforce > 0)
|
||||
if (throwhitsound)
|
||||
playsound(hit_atom, throwhitsound, volume, TRUE, -1)
|
||||
else if(hitsound)
|
||||
playsound(hit_atom, hitsound, volume, TRUE, -1)
|
||||
else
|
||||
playsound(hit_atom, 'sound/weapons/genhit.ogg',volume, TRUE, -1)
|
||||
else
|
||||
playsound(hit_atom, 'sound/weapons/throwtap.ogg', 1, volume, -1)
|
||||
|
||||
return hit_atom.hitby(src, 0, itempush, throwingdatum=throwingdatum)
|
||||
|
||||
/obj/item/throw_at(atom/target, range, speed, mob/thrower, spin=1, diagonals_first = 0, datum/callback/callback, force, messy_throw = TRUE)
|
||||
@@ -756,6 +778,7 @@ GLOBAL_VAR_INIT(rpg_loot_items, FALSE)
|
||||
..()
|
||||
|
||||
/obj/item/proc/microwave_act(obj/machinery/microwave/M)
|
||||
SEND_SIGNAL(src, COMSIG_ITEM_MICROWAVE_ACT, M)
|
||||
if(istype(M) && M.dirty < 100)
|
||||
M.dirty++
|
||||
|
||||
@@ -918,11 +941,13 @@ GLOBAL_VAR_INIT(rpg_loot_items, FALSE)
|
||||
// if w_volume is 0 you fucked up anyways lol
|
||||
return w_volume || AUTO_SCALE_VOLUME(w_class)
|
||||
|
||||
/obj/item/proc/embedded(mob/living/carbon/human/embedded_mob)
|
||||
/obj/item/proc/embedded(atom/embedded_target)
|
||||
return
|
||||
|
||||
/obj/item/proc/unembedded()
|
||||
return
|
||||
if(item_flags & DROPDEL)
|
||||
QDEL_NULL(src)
|
||||
return TRUE
|
||||
|
||||
/**
|
||||
* Sets our slowdown and updates equipment slowdown of any mob we're equipped on.
|
||||
@@ -938,3 +963,135 @@ GLOBAL_VAR_INIT(rpg_loot_items, FALSE)
|
||||
. = ..()
|
||||
if(var_name == NAMEOF(src, slowdown))
|
||||
set_slowdown(var_value) //don't care if it's a duplicate edit as slowdown'll be set, do it anyways to force normal behavior.
|
||||
/**
|
||||
* Does the current embedding var meet the criteria for being harmless? Namely, does it explicitly define the pain multiplier and jostle pain mult to be 0? If so, return true.
|
||||
*
|
||||
*/
|
||||
/obj/item/proc/isEmbedHarmless()
|
||||
if(embedding)
|
||||
return !isnull(embedding["pain_mult"]) && !isnull(embedding["jostle_pain_mult"]) && embedding["pain_mult"] == 0 && embedding["jostle_pain_mult"] == 0
|
||||
|
||||
///In case we want to do something special (like self delete) upon failing to embed in something, return true
|
||||
/obj/item/proc/failedEmbed()
|
||||
if(item_flags & DROPDEL)
|
||||
QDEL_NULL(src)
|
||||
return TRUE
|
||||
|
||||
/**
|
||||
|
||||
|
||||
|
||||
* tryEmbed() is for when you want to try embedding something without dealing with the damage + hit messages of calling hitby() on the item while targetting the target.
|
||||
|
||||
|
||||
|
||||
*
|
||||
|
||||
|
||||
|
||||
* Really, this is used mostly with projectiles with shrapnel payloads, from [/datum/element/embed/proc/checkEmbedProjectile], and called on said shrapnel. Mostly acts as an intermediate between different embed elements.
|
||||
|
||||
|
||||
|
||||
*
|
||||
|
||||
|
||||
|
||||
* Arguments:
|
||||
|
||||
|
||||
|
||||
* * target- Either a body part, a carbon, or a closed turf. What are we hitting?
|
||||
|
||||
|
||||
|
||||
* * forced- Do we want this to go through 100%?
|
||||
|
||||
|
||||
|
||||
*/
|
||||
|
||||
|
||||
|
||||
/obj/item/proc/tryEmbed(atom/target, forced=FALSE, silent=FALSE)
|
||||
|
||||
|
||||
|
||||
if(!isbodypart(target) && !iscarbon(target) && !isclosedturf(target))
|
||||
|
||||
|
||||
|
||||
return
|
||||
|
||||
|
||||
|
||||
if(!forced && !LAZYLEN(embedding))
|
||||
|
||||
|
||||
|
||||
return
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
if(SEND_SIGNAL(src, COMSIG_EMBED_TRY_FORCE, target, forced, silent))
|
||||
|
||||
|
||||
|
||||
return TRUE
|
||||
|
||||
|
||||
|
||||
failedEmbed()
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
///For when you want to disable an item's embedding capabilities (like transforming weapons and such), this proc will detach any active embed elements from it.
|
||||
|
||||
|
||||
|
||||
/obj/item/proc/disableEmbedding()
|
||||
|
||||
|
||||
|
||||
SEND_SIGNAL(src, COMSIG_ITEM_DISABLE_EMBED)
|
||||
|
||||
|
||||
|
||||
return
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
///For when you want to add/update the embedding on an item. Uses the vars in [/obj/item/embedding], and defaults to config values for values that aren't set. Will automatically detach previous embed elements on this item.
|
||||
|
||||
|
||||
|
||||
/obj/item/proc/updateEmbedding()
|
||||
if(!islist(embedding) || !LAZYLEN(embedding))
|
||||
return
|
||||
|
||||
AddElement(/datum/element/embed,\
|
||||
embed_chance = (!isnull(embedding["embed_chance"]) ? embedding["embed_chance"] : EMBED_CHANCE),\
|
||||
fall_chance = (!isnull(embedding["fall_chance"]) ? embedding["fall_chance"] : EMBEDDED_ITEM_FALLOUT),\
|
||||
pain_chance = (!isnull(embedding["pain_chance"]) ? embedding["pain_chance"] : EMBEDDED_PAIN_CHANCE),\
|
||||
pain_mult = (!isnull(embedding["pain_mult"]) ? embedding["pain_mult"] : EMBEDDED_PAIN_MULTIPLIER),\
|
||||
remove_pain_mult = (!isnull(embedding["remove_pain_mult"]) ? embedding["remove_pain_mult"] : EMBEDDED_UNSAFE_REMOVAL_PAIN_MULTIPLIER),\
|
||||
rip_time = (!isnull(embedding["rip_time"]) ? embedding["rip_time"] : EMBEDDED_UNSAFE_REMOVAL_TIME),\
|
||||
ignore_throwspeed_threshold = (!isnull(embedding["ignore_throwspeed_threshold"]) ? embedding["ignore_throwspeed_threshold"] : FALSE),\
|
||||
impact_pain_mult = (!isnull(embedding["impact_pain_mult"]) ? embedding["impact_pain_mult"] : EMBEDDED_IMPACT_PAIN_MULTIPLIER),\
|
||||
jostle_chance = (!isnull(embedding["jostle_chance"]) ? embedding["jostle_chance"] : EMBEDDED_JOSTLE_CHANCE),\
|
||||
jostle_pain_mult = (!isnull(embedding["jostle_pain_mult"]) ? embedding["jostle_pain_mult"] : EMBEDDED_JOSTLE_PAIN_MULTIPLIER),\
|
||||
pain_stam_pct = (!isnull(embedding["pain_stam_pct"]) ? embedding["pain_stam_pct"] : EMBEDDED_PAIN_STAM_PCT),\
|
||||
embed_chance_turf_mod = (!isnull(embedding["embed_chance_turf_mod"]) ? embedding["embed_chance_turf_mod"] : EMBED_CHANCE_TURF_MOD))
|
||||
return TRUE
|
||||
@@ -83,7 +83,7 @@
|
||||
/obj/item/card/emag/bluespace
|
||||
name = "bluespace cryptographic sequencer"
|
||||
desc = "It's a blue card with a magnetic strip attached to some circuitry. It appears to have some sort of transmitter attached to it."
|
||||
color = rgb(40, 130, 255)
|
||||
icon_state = "emag_bs"
|
||||
prox_check = FALSE
|
||||
|
||||
/obj/item/card/emag/attack()
|
||||
@@ -166,6 +166,7 @@
|
||||
slot_flags = ITEM_SLOT_ID
|
||||
armor = list("melee" = 0, "bullet" = 0, "laser" = 0, "energy" = 0, "bomb" = 0, "bio" = 0, "rad" = 0, "fire" = 100, "acid" = 100)
|
||||
resistance_flags = FIRE_PROOF | ACID_PROOF
|
||||
var/id_type_name = "identification card"
|
||||
var/mining_points = 0 //For redeeming at mining equipment vendors
|
||||
var/list/access = list()
|
||||
var/registered_name = null // The name registered_name on the card
|
||||
@@ -174,6 +175,8 @@
|
||||
var/bank_support = ID_FREE_BANK_ACCOUNT
|
||||
var/datum/bank_account/registered_account
|
||||
var/obj/machinery/paystand/my_store
|
||||
var/uses_overlays = TRUE
|
||||
var/icon/cached_flat_icon
|
||||
|
||||
/obj/item/card/id/Initialize(mapload)
|
||||
. = ..()
|
||||
@@ -362,20 +365,38 @@
|
||||
/obj/item/card/id/RemoveID()
|
||||
return src
|
||||
|
||||
/*
|
||||
Usage:
|
||||
update_label()
|
||||
Sets the id name to whatever registered_name and assignment is
|
||||
/obj/item/card/id/update_overlays()
|
||||
. = ..()
|
||||
if(!uses_overlays)
|
||||
return
|
||||
cached_flat_icon = null
|
||||
var/job = assignment ? ckey(GetJobName()) : null
|
||||
if(registered_name == "Captain")
|
||||
job = "captain"
|
||||
if(registered_name && registered_name != "Captain")
|
||||
. += mutable_appearance(icon, "assigned")
|
||||
if(job)
|
||||
. += mutable_appearance(icon, "id[job]")
|
||||
|
||||
/obj/item/card/id/proc/get_cached_flat_icon()
|
||||
if(!cached_flat_icon)
|
||||
cached_flat_icon = getFlatIcon(src)
|
||||
return cached_flat_icon
|
||||
|
||||
|
||||
/obj/item/card/id/get_examine_string(mob/user, thats = FALSE)
|
||||
if(uses_overlays)
|
||||
return "[icon2html(get_cached_flat_icon(), user)] [thats? "That's ":""][get_examine_name(user)]" //displays all overlays in chat
|
||||
return ..()
|
||||
|
||||
update_label("John Doe", "Clowny")
|
||||
Properly formats the name and occupation and sets the id name to the arguments
|
||||
*/
|
||||
/obj/item/card/id/proc/update_label(newname, newjob)
|
||||
if(newname || newjob)
|
||||
name = "[(!newname) ? "identification card" : "[newname]'s ID Card"][(!newjob) ? "" : " ([newjob])"]"
|
||||
update_icon()
|
||||
return
|
||||
|
||||
name = "[(!registered_name) ? "identification card" : "[registered_name]'s ID Card"][(!assignment) ? "" : " ([assignment])"]"
|
||||
update_icon()
|
||||
|
||||
/obj/item/card/id/silver
|
||||
name = "silver identification card"
|
||||
@@ -388,6 +409,7 @@ update_label("John Doe", "Clowny")
|
||||
/obj/item/card/id/silver/reaper
|
||||
name = "Thirteen's ID Card (Reaper)"
|
||||
access = list(ACCESS_MAINT_TUNNELS)
|
||||
icon_state = "reaper"
|
||||
assignment = "Reaper"
|
||||
registered_name = "Thirteen"
|
||||
|
||||
@@ -539,7 +561,7 @@ update_label("John Doe", "Clowny")
|
||||
/obj/item/card/id/ert
|
||||
name = "\improper CentCom ID"
|
||||
desc = "An ERT ID card."
|
||||
icon_state = "centcom"
|
||||
icon_state = "ert_commander"
|
||||
registered_name = "Emergency Response Team Commander"
|
||||
assignment = "Emergency Response Team Commander"
|
||||
|
||||
@@ -548,6 +570,7 @@ update_label("John Doe", "Clowny")
|
||||
. = ..()
|
||||
|
||||
/obj/item/card/id/ert/Security
|
||||
icon_state = "ert_security"
|
||||
registered_name = "Security Response Officer"
|
||||
assignment = "Security Response Officer"
|
||||
|
||||
@@ -556,6 +579,7 @@ update_label("John Doe", "Clowny")
|
||||
. = ..()
|
||||
|
||||
/obj/item/card/id/ert/Engineer
|
||||
icon_state = "ert_engineer"
|
||||
registered_name = "Engineer Response Officer"
|
||||
assignment = "Engineer Response Officer"
|
||||
|
||||
@@ -564,6 +588,7 @@ update_label("John Doe", "Clowny")
|
||||
. = ..()
|
||||
|
||||
/obj/item/card/id/ert/Medical
|
||||
icon_state = "ert_medical"
|
||||
registered_name = "Medical Response Officer"
|
||||
assignment = "Medical Response Officer"
|
||||
|
||||
@@ -572,6 +597,7 @@ update_label("John Doe", "Clowny")
|
||||
. = ..()
|
||||
|
||||
/obj/item/card/id/ert/chaplain
|
||||
icon_state = "ert_chaplain"
|
||||
registered_name = "Religious Response Officer"
|
||||
assignment = "Religious Response Officer"
|
||||
|
||||
@@ -624,40 +650,49 @@ update_label("John Doe", "Clowny")
|
||||
. += "<span class='notice'>Your sentence is up! You're free!</span>"
|
||||
|
||||
/obj/item/card/id/prisoner/one
|
||||
icon_state = "prisoner_001"
|
||||
name = "Prisoner #13-001"
|
||||
registered_name = "Prisoner #13-001"
|
||||
|
||||
/obj/item/card/id/prisoner/two
|
||||
icon_state = "prisoner_002"
|
||||
name = "Prisoner #13-002"
|
||||
registered_name = "Prisoner #13-002"
|
||||
|
||||
/obj/item/card/id/prisoner/three
|
||||
icon_state = "prisoner_003"
|
||||
name = "Prisoner #13-003"
|
||||
registered_name = "Prisoner #13-003"
|
||||
|
||||
/obj/item/card/id/prisoner/four
|
||||
icon_state = "prisoner_004"
|
||||
name = "Prisoner #13-004"
|
||||
registered_name = "Prisoner #13-004"
|
||||
|
||||
/obj/item/card/id/prisoner/five
|
||||
icon_state = "prisoner_005"
|
||||
name = "Prisoner #13-005"
|
||||
registered_name = "Prisoner #13-005"
|
||||
|
||||
/obj/item/card/id/prisoner/six
|
||||
icon_state = "prisoner_006"
|
||||
name = "Prisoner #13-006"
|
||||
registered_name = "Prisoner #13-006"
|
||||
|
||||
/obj/item/card/id/prisoner/seven
|
||||
icon_state = "prisoner_007"
|
||||
name = "Prisoner #13-007"
|
||||
registered_name = "Prisoner #13-007"
|
||||
|
||||
/obj/item/card/id/mining
|
||||
name = "mining ID"
|
||||
icon_state = "retro"
|
||||
access = list(ACCESS_MINING, ACCESS_MINING_STATION, ACCESS_MAILSORTING, ACCESS_MINERAL_STOREROOM)
|
||||
|
||||
/obj/item/card/id/away
|
||||
name = "a perfectly generic identification card"
|
||||
desc = "A perfectly generic identification card. Looks like it could use some flavor."
|
||||
icon_state = "retro"
|
||||
access = list(ACCESS_AWAY_GENERAL)
|
||||
|
||||
/obj/item/card/id/away/hotel
|
||||
@@ -700,6 +735,7 @@ update_label("John Doe", "Clowny")
|
||||
/obj/item/card/id/departmental_budget
|
||||
name = "departmental card (FUCK)"
|
||||
desc = "Provides access to the departmental budget."
|
||||
icon_state = "budgetcard"
|
||||
var/department_ID = ACCOUNT_CIV
|
||||
var/department_name = ACCOUNT_CIV_NAME
|
||||
|
||||
@@ -712,6 +748,7 @@ update_label("John Doe", "Clowny")
|
||||
B.bank_cards += src
|
||||
name = "departmental card ([department_name])"
|
||||
desc = "Provides access to the [department_name]."
|
||||
icon_state = "[lowertext(department_ID)]_budget"
|
||||
SSeconomy.dep_cards += src
|
||||
|
||||
/obj/item/card/id/departmental_budget/Destroy()
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user