mirror of
https://github.com/Bubberstation/Bubberstation.git
synced 2026-08-24 21:48:39 +01:00
Merge remote-tracking branch 'tgstation/master' into upstream-feb12-2026
# Conflicts: # .github/CODEOWNERS # .github/workflows/compile_changelogs.yml # .github/workflows/stale.yml # SQL/database_changelog.md # _maps/map_files/CatwalkStation/CatwalkStation_2023.dmm # code/__DEFINES/atom_hud.dm # code/__DEFINES/inventory.dm # code/__DEFINES/mobs.dm # code/__DEFINES/species_clothing_paths.dm # code/__DEFINES/subsystems.dm # code/__DEFINES/surgery.dm # code/__HELPERS/global_lists.dm # code/_globalvars/lists/maintenance_loot.dm # code/_globalvars/traits/_traits.dm # code/controllers/subsystem/minor_mapping.dm # code/controllers/subsystem/processing/quirks.dm # code/controllers/subsystem/shuttle.dm # code/datums/components/palette.dm # code/datums/components/surgery_initiator.dm # code/datums/diseases/advance/advance.dm # code/datums/hud.dm # code/datums/mood.dm # code/datums/mutations/chameleon.dm # code/datums/quirks/negative_quirks/nyctophobia.dm # code/datums/status_effects/debuffs/debuffs.dm # code/datums/status_effects/debuffs/drunk.dm # code/datums/status_effects/debuffs/slime/slime_leech.dm # code/datums/weather/weather.dm # code/game/data_huds.dm # code/game/objects/items.dm # code/game/objects/items/devices/scanners/health_analyzer.dm # code/game/objects/items/frog_statue.dm # code/game/objects/items/rcd/RLD.dm # code/game/objects/items/robot/items/hypo.dm # code/game/objects/items/stacks/medical.dm # code/game/objects/items/stacks/wrap.dm # code/game/objects/items/storage/garment.dm # code/game/objects/items/tools/medical/defib.dm # code/game/objects/items/weaponry.dm # code/game/objects/items/weaponry/melee/misc.dm # code/game/objects/structures/crates_lockers/closets/secure/security.dm # code/game/objects/structures/curtains.dm # code/game/objects/structures/dresser.dm # code/game/objects/structures/girders.dm # code/game/objects/structures/maintenance.dm # code/game/objects/structures/mirror.dm # code/modules/admin/greyscale_modify_menu.dm # code/modules/admin/verbs/light_debug.dm # code/modules/antagonists/ashwalker/ashwalker.dm # code/modules/antagonists/heretic/knowledge/starting_lore.dm # code/modules/antagonists/ninja/ninjaDrainAct.dm # code/modules/art/paintings.dm # code/modules/client/preferences.dm # code/modules/client/verbs/ooc.dm # code/modules/clothing/head/wig.dm # code/modules/events/disease_outbreak.dm # code/modules/holodeck/holo_effect.dm # code/modules/jobs/job_types/head_of_security.dm # code/modules/jobs/job_types/security_officer.dm # code/modules/library/skill_learning/generic_skillchips/point.dm # code/modules/mining/lavaland/ash_flora.dm # code/modules/mining/lavaland/mining_loot/megafauna/ash_drake.dm # code/modules/mob/dead/new_player/new_player.dm # code/modules/mob/living/basic/guardian/guardian.dm # code/modules/mob/living/basic/space_fauna/space_dragon/space_dragon.dm # code/modules/mob/living/carbon/carbon.dm # code/modules/mob/living/carbon/human/human.dm # code/modules/mob/living/carbon/human/human_defines.dm # code/modules/mob/living/carbon/life.dm # code/modules/mob/living/living.dm # code/modules/mob/living/living_defines.dm # code/modules/mob/mob.dm # code/modules/mob_spawn/ghost_roles/mining_roles.dm # code/modules/mod/mod_control.dm # code/modules/mod/modules/modules_general.dm # code/modules/modular_computers/computers/item/computer_ui.dm # code/modules/paperwork/paper.dm # code/modules/paperwork/paperbin.dm # code/modules/power/lighting/light.dm # code/modules/projectiles/guns/energy/kinetic_accelerator.dm # code/modules/projectiles/projectile.dm # code/modules/reagents/chemistry/reagents/drinks/alcohol_reagents.dm # code/modules/reagents/chemistry/reagents/food_reagents.dm # code/modules/reagents/chemistry/reagents/other_reagents.dm # code/modules/reagents/chemistry/reagents/pyrotechnic_reagents.dm # code/modules/research/xenobiology/crossbreeding/_clothing.dm # code/modules/research/xenobiology/crossbreeding/prismatic.dm # code/modules/surgery/advanced/brainwashing.dm # code/modules/surgery/advanced/lobotomy.dm # code/modules/surgery/amputation.dm # code/modules/surgery/blood_filter.dm # code/modules/surgery/bodyparts/_bodyparts.dm # code/modules/surgery/brain_surgery.dm # code/modules/surgery/cavity_implant.dm # code/modules/surgery/coronary_bypass.dm # code/modules/surgery/gastrectomy.dm # code/modules/surgery/healing.dm # code/modules/surgery/limb_augmentation.dm # code/modules/surgery/organ_manipulation.dm # code/modules/surgery/revival.dm # code/modules/surgery/sleeper_protocol.dm # code/modules/surgery/surgery_helpers.dm # code/modules/surgery/surgery_step.dm # code/modules/unit_tests/_unit_tests.dm # code/modules/unit_tests/designs.dm # code/modules/unit_tests/icon_state_worn.dm # code/modules/unit_tests/screenshots/screenshot_antag_icons_cultist.png # code/modules/unit_tests/screenshots/screenshot_antag_icons_headrevolutionary.png # code/modules/unit_tests/screenshots/screenshot_antag_icons_provocateur.png # code/modules/unit_tests/screenshots/screenshot_husk_body.png # code/modules/unit_tests/screenshots/screenshot_husk_body_missing_limbs.png # icons/map_icons/clothing/head/_head.dmi # icons/map_icons/clothing/shoes.dmi # icons/map_icons/items/_item.dmi # icons/mob/huds/hud.dmi # icons/mob/inhands/64x64_lefthand.dmi # icons/mob/inhands/64x64_righthand.dmi # icons/obj/machines/computer.dmi # tgui/packages/tgui/interfaces/OperatingComputer.jsx # tgui/packages/tgui/interfaces/PreferencesMenu/CharacterPreferences/MainPage.tsx # tgui/packages/tgui/interfaces/PreferencesMenu/types.ts # tgui/packages/tgui/interfaces/SurgeryInitiator.tsx # tools/icon_cutter/check.py
This commit is contained in:
@@ -51,7 +51,7 @@
|
||||
var/list/damage_coeff = list(BRUTE = 1, BURN = 1, TOX = 1, STAMINA = 1, OXY = 1)
|
||||
|
||||
///Verbs used for speaking e.g. "Says" or "Chitters". This can be elementized
|
||||
var/list/speak_emote = list()
|
||||
var/list/speak_emote
|
||||
|
||||
///When someone interacts with the simple animal.
|
||||
///Help-intent verb in present continuous tense.
|
||||
@@ -120,8 +120,9 @@
|
||||
apply_target_randomisation()
|
||||
make_stamina_slowable()
|
||||
|
||||
if(speak_emote)
|
||||
if(LAZYLEN(speak_emote))
|
||||
speak_emote = string_list(speak_emote)
|
||||
damage_coeff = string_assoc_list(damage_coeff)
|
||||
|
||||
///We need to wait for SSair to be initialized before we can check atmos/temp requirements.
|
||||
if(PERFORM_ALL_TESTS(focus_only/atmos_and_temp_requirements) && mapload && !SSair.initialized)
|
||||
@@ -163,7 +164,7 @@
|
||||
return
|
||||
AddElement(/datum/element/attack_zone_randomiser)
|
||||
|
||||
/mob/living/basic/Life(seconds_per_tick = SSMOBS_DT, times_fired)
|
||||
/mob/living/basic/Life(seconds_per_tick = SSMOBS_DT)
|
||||
. = ..()
|
||||
if(staminaloss > 0)
|
||||
adjust_stamina_loss(-stamina_recovery * seconds_per_tick, forced = TRUE)
|
||||
|
||||
@@ -53,7 +53,7 @@
|
||||
visible_message(span_warning("The corpse of [target.name] suddenly rises!"))
|
||||
var/mob/living/basic/blob_minion/zombie/blombie = change_mob_type(zombie_type, loc, new_name = initial(zombie_type.name))
|
||||
blombie.pass_flags |= PASSBLOB //No way to pass the blob_borne info through change_mob_type() to Initilize(), so we just circumvent it here.
|
||||
blombie.faction |= faction //inherit the spore's faction in case it was spawned with a different one (eg gold core)
|
||||
APPLY_FACTION_AND_ALLIES_FROM(blombie, src) //inherit the spore's faction in case it was spawned with a different one (eg gold core)
|
||||
blombie.set_name()
|
||||
if (istype(blombie)) // In case of badmin
|
||||
blombie.consume_corpse(target)
|
||||
|
||||
@@ -117,7 +117,7 @@
|
||||
/// Is our factory dead?
|
||||
var/orphaned = FALSE
|
||||
|
||||
/mob/living/basic/blob_minion/blobbernaut/minion/Life(seconds_per_tick, times_fired)
|
||||
/mob/living/basic/blob_minion/blobbernaut/minion/Life(seconds_per_tick)
|
||||
. = ..()
|
||||
if (!.)
|
||||
return FALSE
|
||||
|
||||
@@ -0,0 +1,173 @@
|
||||
/*
|
||||
|
||||
BLOOD-DRUNK MINER
|
||||
|
||||
Effectively a highly aggressive miner, the blood-drunk miner has very few attacks but compensates by being highly aggressive in its AI as well as damage.
|
||||
|
||||
When the blood-drunk miner dies, it leaves behind the cleaving saw it was using and its kinetic accelerator.
|
||||
|
||||
Difficulty: Medium
|
||||
|
||||
*/
|
||||
/mob/living/basic/boss/blood_drunk_miner
|
||||
name = "blood-drunk miner"
|
||||
desc = "A miner destined to wander forever, engaged in an endless hunt."
|
||||
health = 900
|
||||
maxHealth = 900
|
||||
icon_state = "miner"
|
||||
icon_living = "miner"
|
||||
icon = 'icons/mob/simple/broadMobs.dmi'
|
||||
health_doll_icon = "miner"
|
||||
mob_biotypes = MOB_ORGANIC|MOB_HUMANOID|MOB_SPECIAL|MOB_MINING
|
||||
light_color = COLOR_LIGHT_GRAYISH_RED
|
||||
speak_emote = list("roars")
|
||||
speed = 3
|
||||
pixel_x = -16
|
||||
base_pixel_x = -16
|
||||
basic_mob_flags = DEL_ON_DEATH
|
||||
default_blood_volume = BLOOD_VOLUME_NORMAL
|
||||
gps_name = "Resonant Signal"
|
||||
death_message = "falls to the ground, decaying into glowing particles."
|
||||
death_sound = SFX_BODYFALL
|
||||
move_force = MOVE_FORCE_NORMAL //Miner beeing able to just move structures like bolted doors and glass looks kinda strange
|
||||
|
||||
ai_controller = /datum/ai_controller/blood_drunk_miner
|
||||
|
||||
achievements = list(
|
||||
/datum/award/achievement/boss/blood_miner_kill,
|
||||
/datum/award/achievement/boss/boss_killer,
|
||||
/datum/award/score/blood_miner_score,
|
||||
/datum/award/score/boss_score,
|
||||
)
|
||||
crusher_achievement_type = /datum/award/achievement/boss/blood_miner_crusher
|
||||
victor_memory_type = /datum/memory/megafauna_slayer
|
||||
|
||||
crusher_loot = list(/obj/item/crusher_trophy/miner_eye, /obj/item/knife/hunting/wildhunter)
|
||||
regular_loot = list(/obj/item/melee/cleaving_saw, /obj/item/gun/energy/recharge/kinetic_accelerator)
|
||||
|
||||
/// Their little saw
|
||||
var/obj/item/melee/cleaving_saw/miner/miner_saw
|
||||
/// How many hits of our saw we inflict on the target when we melee on them. Get mutated via the transform weapon ability.
|
||||
var/rapid_melee_hits = 5
|
||||
/// How long must we wait between ranged attacks
|
||||
var/ranged_attack_cooldown_duration = 1.6 SECONDS
|
||||
|
||||
/mob/living/basic/boss/blood_drunk_miner/Initialize(mapload)
|
||||
. = ..()
|
||||
ADD_TRAIT(src, TRAIT_NO_FLOATING_ANIM, INNATE_TRAIT)
|
||||
RegisterSignal(src, COMSIG_MOVABLE_PRE_MOVE, PROC_REF(on_premove))
|
||||
AddElement(/datum/element/relay_attackers)
|
||||
AddElement(/datum/element/footstep, footstep_type = FOOTSTEP_MOB_HEAVY)
|
||||
|
||||
RegisterSignal(src, COMSIG_HOSTILE_PRE_ATTACKINGTARGET, PROC_REF(attack_override))
|
||||
|
||||
miner_saw = new(src)
|
||||
RegisterSignal(miner_saw, COMSIG_PREQDELETED, PROC_REF(on_saw_deleted))
|
||||
RegisterSignal(miner_saw, COMSIG_MOVABLE_PRE_MOVE, PROC_REF(on_saw_premove))
|
||||
|
||||
grant_actions_by_list(get_innate_actions())
|
||||
ai_controller.set_blackboard_key(BB_BDM_RANGED_ATTACK_COOLDOWN, ranged_attack_cooldown_duration)
|
||||
RegisterSignals(ai_controller, list(AI_CONTROLLER_BEHAVIOR_QUEUED(/datum/ai_behavior/basic_melee_attack), AI_CONTROLLER_BEHAVIOR_QUEUED(/datum/ai_behavior/targeted_mob_ability)), PROC_REF(handle_saw_transformation))
|
||||
|
||||
RegisterSignal(src, COMSIG_LIVING_DROP_LOOT, PROC_REF(death_effect))
|
||||
|
||||
AddComponent(/datum/component/boss_music, 'sound/music/boss/bdm_boss.ogg', COMSIG_AI_BLACKBOARD_KEY_SET(BB_BASIC_MOB_CURRENT_TARGET))
|
||||
|
||||
/// Block deletion of their saw under normal circumstances. It is fused to their hands as far as we're concerned.
|
||||
/mob/living/basic/boss/blood_drunk_miner/proc/on_saw_deleted(datum/source, force)
|
||||
SIGNAL_HANDLER
|
||||
|
||||
if(!force)
|
||||
return TRUE
|
||||
|
||||
/mob/living/basic/boss/blood_drunk_miner/Destroy(force)
|
||||
UnregisterSignal(miner_saw, list(COMSIG_PREQDELETED, COMSIG_MOVABLE_PRE_MOVE)) // unblock deletion, we are dead.
|
||||
QDEL_NULL(miner_saw)
|
||||
return ..()
|
||||
|
||||
/// Returns a list of innate actions for the blood-drunk miner.
|
||||
/mob/living/basic/boss/blood_drunk_miner/proc/get_innate_actions()
|
||||
var/static/list/innate_abilities = list(
|
||||
/datum/action/cooldown/mob_cooldown/dash = BB_BDM_DASH_ABILITY,
|
||||
/datum/action/cooldown/mob_cooldown/projectile_attack/kinetic_accelerator = BB_BDM_KINETIC_ACCELERATOR_ABILITY,
|
||||
/datum/action/cooldown/mob_cooldown/dash_attack = BB_BDM_DASH_ATTACK_ABILITY,
|
||||
/datum/action/cooldown/mob_cooldown/transform_weapon = BB_BDM_TRANSFORM_WEAPON_ABILITY,
|
||||
)
|
||||
return innate_abilities
|
||||
|
||||
/// Invokes the transform weapon ability when signaled by the AI controller.
|
||||
/mob/living/basic/boss/blood_drunk_miner/proc/handle_saw_transformation()
|
||||
SIGNAL_HANDLER
|
||||
|
||||
INVOKE_ASYNC(ai_controller.blackboard[BB_BDM_TRANSFORM_WEAPON_ABILITY], TYPE_PROC_REF(/datum/action, Trigger), src, NONE)
|
||||
|
||||
/mob/living/basic/boss/blood_drunk_miner/ex_act(severity, target)
|
||||
var/datum/action/cooldown/mob_cooldown/dash_ability = ai_controller.blackboard[BB_BDM_DASH_ABILITY]
|
||||
if(dash_ability.Trigger(target = target))
|
||||
return FALSE
|
||||
return ..()
|
||||
|
||||
/mob/living/basic/boss/blood_drunk_miner/do_attack_animation(atom/attacked_atom, visual_effect_icon, obj/item/used_item, no_effect)
|
||||
if(!used_item && !isturf(attacked_atom))
|
||||
used_item = miner_saw
|
||||
return ..()
|
||||
|
||||
/mob/living/basic/boss/blood_drunk_miner/adjust_health(amount, updating_health = TRUE, forced = FALSE)
|
||||
var/adjustment_amount = amount * 0.1
|
||||
if(world.time + adjustment_amount > next_move)
|
||||
changeNext_move(adjustment_amount) //attacking it interrupts it attacking, but only briefly
|
||||
return ..()
|
||||
|
||||
/// Handles spawning a death effect when the blood-drunk miner dies. Tied to COMSIG_LIVING_DROP_LOOT so the timings of spawning the effect should approximately work out with the loot appearing.
|
||||
/mob/living/basic/boss/blood_drunk_miner/proc/death_effect(datum/source, list/spawn_loot, gibbed)
|
||||
SIGNAL_HANDLER
|
||||
new /obj/effect/temp_visual/dir_setting/miner_death(loc, dir)
|
||||
|
||||
/// Prevent running into a chasm and other undesirable movements.
|
||||
/mob/living/basic/boss/blood_drunk_miner/proc/on_premove(datum/source, atom/new_location)
|
||||
if(isnull(new_location))
|
||||
return
|
||||
|
||||
if(new_location.z != z)
|
||||
return
|
||||
|
||||
var/turf/open/locus = get_turf(new_location)
|
||||
if(!ischasm(locus) || locus.can_cross_safely(src)) // if it's not a chasm we don't care to check the proc.
|
||||
return
|
||||
|
||||
return COMPONENT_MOVABLE_BLOCK_PRE_MOVE
|
||||
|
||||
/// Prevent their saw from being moved at all
|
||||
/mob/living/basic/boss/blood_drunk_miner/proc/on_saw_premove(datum/source, atom/new_location)
|
||||
return COMPONENT_MOVABLE_BLOCK_PRE_MOVE
|
||||
|
||||
/// Handles our attack behavior when we're doing melee attacks to override the default basic melee attack behavior when our AI calls upon us to use it.
|
||||
/// Namely, we just use the miner saw to rapidly hit the target multiple times
|
||||
/mob/living/basic/boss/blood_drunk_miner/proc/attack_override(mob/living/source, atom/target, proximity, modifiers)
|
||||
SIGNAL_HANDLER
|
||||
if(!istype(target, /mob/living))
|
||||
return
|
||||
|
||||
var/mob/living/victim = target
|
||||
if(should_devour(target))
|
||||
devour(target)
|
||||
return COMPONENT_HOSTILE_NO_ATTACK
|
||||
|
||||
changeNext_move(CLICK_CD_MELEE)
|
||||
victim.visible_message(
|
||||
span_danger("[src] slashes at [victim] with [p_their()] cleaving saw!"),
|
||||
span_userdanger("You are slashed at by [src]'s cleaving saw!"),
|
||||
)
|
||||
|
||||
var/datum/callback/melee_callback = CALLBACK(miner_saw, TYPE_PROC_REF(/obj/item/melee/cleaving_saw/miner, melee_attack_chain), src, victim, modifiers)
|
||||
var/delay = 0.2 SECONDS
|
||||
for(var/i in 1 to rapid_melee_hits)
|
||||
addtimer(melee_callback, (i - 1) * delay)
|
||||
|
||||
post_attack_effects(victim, modifiers)
|
||||
|
||||
return COMPONENT_HOSTILE_NO_ATTACK
|
||||
|
||||
/// Hook for potential additional behaviors after attacking
|
||||
/mob/living/basic/boss/blood_drunk_miner/proc/post_attack_effects(mob/living/victim, list/modifiers)
|
||||
return
|
||||
@@ -0,0 +1,66 @@
|
||||
/// AI for handling blood-drunk miner behavior
|
||||
/// General consideration is as follows:
|
||||
/// - If in PKA range, shoot PKA
|
||||
/// - If not in PKA range, dash attack on the target
|
||||
/// - If in melee range, use melee attacks (depending on saw state)
|
||||
/// - After attacks, transform saw state from open to closed.
|
||||
/datum/ai_controller/blood_drunk_miner
|
||||
blackboard = list(
|
||||
BB_TARGETING_STRATEGY = /datum/targeting_strategy/basic/no_gutted_mobs,
|
||||
BB_TARGET_MINIMUM_STAT = DEAD,
|
||||
BB_AGGRO_RANGE = 18, // oh fuck oh shit
|
||||
BB_BDM_RANGED_ATTACK_COOLDOWN = 0,
|
||||
)
|
||||
|
||||
movement_delay = 0.3 SECONDS
|
||||
ai_movement = /datum/ai_movement/basic_avoidance
|
||||
idle_behavior = /datum/idle_behavior/idle_random_walk
|
||||
planning_subtrees = list(
|
||||
/datum/ai_planning_subtree/escape_captivity,
|
||||
/datum/ai_planning_subtree/simple_find_target,
|
||||
/datum/ai_planning_subtree/attack_obstacle_in_path,
|
||||
/datum/ai_planning_subtree/targeted_mob_ability/blood_drunk/shoot_pka,
|
||||
/datum/ai_planning_subtree/targeted_mob_ability/blood_drunk/dash_attack,
|
||||
/datum/ai_planning_subtree/basic_melee_attack_subtree,
|
||||
)
|
||||
|
||||
/// Parent type that contains key logic important for subsequent abilities
|
||||
/datum/ai_planning_subtree/targeted_mob_ability/blood_drunk
|
||||
/// Range where we determine what distance we're at. If higher, we consider ourselves out of PKA range and will dash attack instead. Inclusive when it comes to choosing to shoot PKA.
|
||||
var/pka_range = 3
|
||||
|
||||
/// Check our blackboard to see if we are able to use a ranged ability in the first place
|
||||
/datum/ai_planning_subtree/targeted_mob_ability/blood_drunk/additional_ability_checks(datum/ai_controller/controller, datum/action/cooldown/using_action)
|
||||
. = ..()
|
||||
if(controller.blackboard[BB_BDM_RANGED_ATTACK_COOLDOWN] > world.time)
|
||||
return FALSE
|
||||
controller.override_blackboard_key(BB_BDM_RANGED_ATTACK_COOLDOWN, world.time + controller.blackboard[BB_BDM_RANGED_ATTACK_COOLDOWN_DURATION])
|
||||
|
||||
/// The BDM will preferentially shoot its PKA within range over other abilities
|
||||
/datum/ai_planning_subtree/targeted_mob_ability/blood_drunk/shoot_pka
|
||||
ability_key = BB_BDM_KINETIC_ACCELERATOR_ABILITY
|
||||
|
||||
/datum/ai_planning_subtree/targeted_mob_ability/blood_drunk/shoot_pka/additional_ability_checks(datum/ai_controller/controller, datum/action/cooldown/using_action)
|
||||
. = ..()
|
||||
// do not shoot the PKA if we are not in the right range
|
||||
var/mob/living/pawn = controller.pawn
|
||||
var/mob/living/victim = controller.blackboard[BB_BASIC_MOB_CURRENT_TARGET]
|
||||
if(get_dist(pawn, victim) >= pka_range)
|
||||
return FALSE
|
||||
return TRUE
|
||||
|
||||
/// The BDM will dash attack if not in PKA range
|
||||
/datum/ai_planning_subtree/targeted_mob_ability/blood_drunk/dash_attack
|
||||
ability_key = BB_BDM_DASH_ATTACK_ABILITY
|
||||
|
||||
/datum/ai_planning_subtree/targeted_mob_ability/blood_drunk/dash_attack/additional_ability_checks(datum/ai_controller/controller, datum/action/cooldown/using_action)
|
||||
. = ..()
|
||||
// only dash attack if we are out of PKA range
|
||||
var/mob/living/pawn = controller.pawn
|
||||
var/mob/living/victim = controller.blackboard[BB_BASIC_MOB_CURRENT_TARGET]
|
||||
if(get_dist(pawn, victim) < pka_range)
|
||||
return FALSE
|
||||
return TRUE
|
||||
|
||||
/datum/ai_controller/blood_drunk_miner/doom
|
||||
movement_delay = 0.8 SECONDS
|
||||
@@ -0,0 +1,35 @@
|
||||
/// A slightly nerfed saw as the normal one is much too murdery.
|
||||
/obj/item/melee/cleaving_saw/miner
|
||||
force = 6
|
||||
open_force = 10
|
||||
|
||||
/obj/item/melee/cleaving_saw/miner/attack(mob/living/target, mob/living/carbon/human/user)
|
||||
target.add_stun_absorption(source = "miner", duration = 1 SECONDS, priority = INFINITY)
|
||||
return ..()
|
||||
|
||||
/obj/projectile/kinetic/miner
|
||||
damage = 20
|
||||
speed = 1.1
|
||||
icon_state = "ka_tracer"
|
||||
range = 4
|
||||
|
||||
/obj/effect/temp_visual/dir_setting/miner_death
|
||||
icon_state = "miner_death"
|
||||
duration = 15
|
||||
|
||||
/obj/effect/temp_visual/dir_setting/miner_death/Initialize(mapload, set_dir)
|
||||
. = ..()
|
||||
INVOKE_ASYNC(src, PROC_REF(fade_out))
|
||||
|
||||
/obj/effect/temp_visual/dir_setting/miner_death/proc/fade_out()
|
||||
var/matrix/our_matrix = new
|
||||
our_matrix.Turn(pick(90, 270))
|
||||
var/final_dir = dir
|
||||
if(dir & (EAST|WEST)) //Facing east or west
|
||||
final_dir = pick(NORTH, SOUTH) //So you fall on your side rather than your face or ass
|
||||
|
||||
animate(src, transform = our_matrix, pixel_y = -6, dir = final_dir, time = 2, easing = QUAD_EASING)
|
||||
sleep(0.5 SECONDS)
|
||||
animate(src, color = list("#A7A19E", "#A7A19E", "#A7A19E", list(0, 0, 0)), time = 10, easing = SINE_EASING|EASE_IN, flags = ANIMATION_PARALLEL)
|
||||
sleep(0.4 SECONDS)
|
||||
animate(src, alpha = 0, time = 6, easing = SINE_EASING|EASE_OUT, flags = ANIMATION_PARALLEL)
|
||||
@@ -0,0 +1,35 @@
|
||||
#define HUNTER_DASH_PROBABILITY 12
|
||||
|
||||
/// heals slightly on melee hits
|
||||
/mob/living/basic/boss/blood_drunk_miner/guidance
|
||||
|
||||
/mob/living/basic/boss/blood_drunk_miner/guidance/attack_override(mob/living/source, atom/target, proximity, modifiers)
|
||||
. = ..()
|
||||
if(. & COMPONENT_HOSTILE_NO_ATTACK)
|
||||
adjust_health(-2 * rapid_melee_hits)
|
||||
|
||||
/// Better at dash attacking
|
||||
/mob/living/basic/boss/blood_drunk_miner/hunter
|
||||
|
||||
/mob/living/basic/boss/blood_drunk_miner/hunter/post_attack_effects(mob/living/victim, list/modifiers)
|
||||
if(!prob(HUNTER_DASH_PROBABILITY))
|
||||
return
|
||||
|
||||
var/dash_attack = ai_controller.blackboard[BB_BDM_DASH_ATTACK_ABILITY]
|
||||
if(!isnull(dash_attack))
|
||||
INVOKE_ASYNC(dash_attack, TYPE_PROC_REF(/datum/action, Trigger), src, NONE, victim)
|
||||
|
||||
/mob/living/basic/boss/blood_drunk_miner/doom
|
||||
name = "hostile-environment miner"
|
||||
desc = "A miner destined to hop across dimensions for all eternity, hunting anomalous creatures."
|
||||
speed = 8
|
||||
ranged_attack_cooldown_duration = 0.8 SECONDS
|
||||
ai_controller = /datum/ai_controller/blood_drunk_miner/doom
|
||||
|
||||
/mob/living/basic/boss/blood_drunk_miner/doom/Initialize(mapload)
|
||||
. = ..()
|
||||
var/datum/action/cooldown/dash_ability = ai_controller.blackboard[BB_BDM_DASH_ABILITY]
|
||||
if(!isnull(dash_ability))
|
||||
dash_ability.cooldown_time = 0.8 SECONDS
|
||||
|
||||
#undef HUNTER_DASH_PROBABILITY
|
||||
@@ -20,32 +20,38 @@
|
||||
flags_1 = PREVENT_CONTENTS_EXPLOSION_1
|
||||
/// Name for the GPS signal of the megafauna
|
||||
var/gps_name = null
|
||||
/// What crusher trophy this mob drops, if any
|
||||
var/crusher_loot
|
||||
/// What crusher trophy/trophies this mob drops, if any
|
||||
/// Should be wrapped in a list for sanity when we pass it to the element.
|
||||
var/list/crusher_loot = null
|
||||
/// Loot dropped on death in normal circumstances
|
||||
var/list/regular_loot = list()
|
||||
|
||||
/// What achievements do we give our defeater?
|
||||
var/list/achievements = null
|
||||
/// What type of achievement we give for crusher kills, if any.
|
||||
var/crusher_achievement_type = null
|
||||
/// What memory to give to victor who have killed us, if any.
|
||||
var/victor_memory_type = null
|
||||
|
||||
/mob/living/basic/boss/Initialize(mapload)
|
||||
. = ..()
|
||||
AddElement(/datum/element/wall_tearer, tear_time = 1 SECONDS)
|
||||
if(gps_name)
|
||||
AddComponent(/datum/component/gps, gps_name)
|
||||
if(crusher_loot)
|
||||
AddElement(\
|
||||
/datum/element/crusher_loot,\
|
||||
trophy_type = crusher_loot,\
|
||||
guaranteed_drop = 0.6,\
|
||||
drop_immediately = basic_mob_flags & DEL_ON_DEATH,\
|
||||
)
|
||||
ADD_TRAIT(src, TRAIT_SPACEWALK, INNATE_TRAIT)
|
||||
add_traits(list(TRAIT_NO_TELEPORT, TRAIT_MARTIAL_ARTS_IMMUNE, TRAIT_LAVA_IMMUNE,TRAIT_ASHSTORM_IMMUNE, TRAIT_NO_FLOATING_ANIM), MEGAFAUNA_TRAIT)
|
||||
add_traits(list(TRAIT_NO_TELEPORT, TRAIT_MARTIAL_ARTS_IMMUNE, TRAIT_LAVA_IMMUNE, TRAIT_ASHSTORM_IMMUNE, TRAIT_NO_FLOATING_ANIM), MEGAFAUNA_TRAIT)
|
||||
AddComponent(/datum/component/seethrough_mob)
|
||||
AddElement(/datum/element/simple_flying)
|
||||
AddElement(/datum/element/death_drops, string_list(regular_loot))
|
||||
handle_crusher_loot()
|
||||
handle_achievements()
|
||||
|
||||
/mob/living/basic/boss/gib()
|
||||
if(health > 0)
|
||||
return
|
||||
return ..()
|
||||
|
||||
/mob/living/basic/boss/dust(just_ash, drop_items, force)
|
||||
/mob/living/basic/boss/dust(just_ash, drop_items, give_moodlet, force)
|
||||
if(!force && health > 0)
|
||||
return
|
||||
return ..()
|
||||
@@ -55,13 +61,30 @@
|
||||
return
|
||||
return ..()
|
||||
|
||||
/mob/living/basic/boss/ex_act(severity, target)
|
||||
switch (severity)
|
||||
if (EXPLODE_DEVASTATE)
|
||||
adjust_brute_loss(250)
|
||||
|
||||
if (EXPLODE_HEAVY)
|
||||
adjust_brute_loss(100)
|
||||
|
||||
if (EXPLODE_LIGHT)
|
||||
adjust_brute_loss(50)
|
||||
|
||||
return TRUE
|
||||
|
||||
/mob/living/basic/boss/early_melee_attack(mob/living/target, list/modifiers, ignore_cooldown)
|
||||
. = ..()
|
||||
if(!. || !istype(target))
|
||||
return
|
||||
if(target.stat == DEAD || (target.health <= HEALTH_THRESHOLD_DEAD && HAS_TRAIT(target, TRAIT_NODEATH)))
|
||||
if(should_devour(target))
|
||||
devour(target)
|
||||
|
||||
/// Determines if this mob is worth devouring
|
||||
/mob/living/basic/boss/proc/should_devour(mob/living/victim)
|
||||
return victim.stat == DEAD || (victim.health <= HEALTH_THRESHOLD_DEAD && HAS_TRAIT(victim, TRAIT_NODEATH))
|
||||
|
||||
/// Devours a target and restores health to the megafauna
|
||||
/mob/living/basic/boss/proc/devour(mob/living/victim)
|
||||
if(isnull(victim) || victim.has_status_effect(/datum/status_effect/gutted))
|
||||
@@ -79,20 +102,28 @@
|
||||
victim.apply_status_effect(/datum/status_effect/gutted)
|
||||
return TRUE
|
||||
|
||||
/// Small little taunt when we epically troll someone
|
||||
/mob/living/basic/boss/proc/celebrate_kill(mob/living/poor_sap)
|
||||
visible_message(
|
||||
span_danger("[src] disembowels [poor_sap]!"),
|
||||
span_userdanger("You feast on [poor_sap]'s organs, restoring your health!"))
|
||||
span_userdanger("You feast on [poor_sap]'s organs, restoring your health!"),
|
||||
)
|
||||
|
||||
/mob/living/basic/boss/ex_act(severity, target)
|
||||
switch (severity)
|
||||
if (EXPLODE_DEVASTATE)
|
||||
adjust_brute_loss(250)
|
||||
/// Handles adding all relevant achievements when applicable (probably when we are defeated)
|
||||
/// Achievements being null/no length is handled in the element itself.
|
||||
/mob/living/basic/boss/proc/handle_achievements()
|
||||
if(length(achievements) <= 0)
|
||||
return
|
||||
AddElement(/datum/element/kill_achievement, string_list(achievements), crusher_achievement_type, victor_memory_type)
|
||||
|
||||
if (EXPLODE_HEAVY)
|
||||
adjust_brute_loss(100)
|
||||
/// Handles adding crusher loot when applicable (probably when we are defeated)
|
||||
/mob/living/basic/boss/proc/handle_crusher_loot()
|
||||
if(isnull(crusher_loot))
|
||||
return
|
||||
AddElement(\
|
||||
/datum/element/crusher_loot,\
|
||||
trophy_type = string_list(crusher_loot),\
|
||||
guaranteed_drop = 0.6,\
|
||||
drop_immediately = basic_mob_flags & DEL_ON_DEATH,\
|
||||
)
|
||||
|
||||
if (EXPLODE_LIGHT)
|
||||
adjust_brute_loss(50)
|
||||
|
||||
return TRUE
|
||||
|
||||
@@ -21,8 +21,18 @@
|
||||
speed = 3.5 //dont make this any faster PLEASE
|
||||
gps_name = "L-4 Biohazard Beacon"
|
||||
ai_controller = /datum/ai_controller/basic_controller/thing_boss
|
||||
crusher_loot = /obj/item/crusher_trophy/flesh_glob
|
||||
crusher_loot = list(/obj/item/crusher_trophy/flesh_glob)
|
||||
mouse_opacity = MOUSE_OPACITY_OPAQUE
|
||||
|
||||
achievements = list(
|
||||
/datum/award/achievement/boss/boss_killer,
|
||||
/datum/award/achievement/boss/thething_kill,
|
||||
/datum/award/score/boss_score,
|
||||
/datum/award/score/thething_score,
|
||||
)
|
||||
crusher_achievement_type = /datum/award/achievement/boss/thething_crusher
|
||||
victor_memory_type = /datum/memory/megafauna_slayer
|
||||
|
||||
/// Current phase of the boss fight
|
||||
var/phase = 1
|
||||
/// Time the Thing will be invulnerable between phases
|
||||
@@ -41,13 +51,7 @@
|
||||
|
||||
/mob/living/basic/boss/thing/Initialize(mapload)
|
||||
. = ..()
|
||||
var/static/list/achievements = list(
|
||||
/datum/award/achievement/boss/boss_killer,
|
||||
/datum/award/achievement/boss/thething_kill,
|
||||
/datum/award/score/boss_score,
|
||||
/datum/award/score/thething_score,
|
||||
)
|
||||
AddElement(/datum/element/kill_achievement, achievements, /datum/award/achievement/boss/thething_crusher, /datum/memory/megafauna_slayer)
|
||||
|
||||
AddElement(/datum/element/death_drops, /obj/item/keycard/thing_boss, FALSE)
|
||||
|
||||
var/static/list/innate_actions = list(
|
||||
|
||||
@@ -102,6 +102,10 @@ GLOBAL_LIST_INIT(command_strings, list(
|
||||
)
|
||||
///name of the UI we will attempt to open
|
||||
var/bot_ui = "SimpleBot"
|
||||
// The faction of the bot before it inherited the pai's faction
|
||||
var/list/original_faction
|
||||
// The allies of the bot before it inherited the pai's faction
|
||||
var/list/original_allies
|
||||
/// If true we will offer this
|
||||
COOLDOWN_DECLARE(offer_ghosts_cooldown)
|
||||
|
||||
@@ -112,7 +116,7 @@ GLOBAL_LIST_INIT(command_strings, list(
|
||||
AddElement(/datum/element/ai_retaliate)
|
||||
RegisterSignal(src, COMSIG_MOVABLE_MOVED, PROC_REF(handle_loop_movement))
|
||||
RegisterSignal(src, COMSIG_ATOM_WAS_ATTACKED, PROC_REF(after_attacked))
|
||||
RegisterSignal(src, COMSIG_MOB_TRIED_ACCESS, PROC_REF(attempt_access))
|
||||
RegisterSignal(src, COMSIG_MOB_RETRIEVE_ACCESS, PROC_REF(retrieve_access))
|
||||
add_traits(list(TRAIT_NO_GLIDE, TRAIT_SILICON_EMOTES_ALLOWED), INNATE_TRAIT)
|
||||
LoadComponent(/datum/component/bloodysoles/bot)
|
||||
GLOB.bots_list += src
|
||||
@@ -706,7 +710,9 @@ GLOBAL_LIST_INIT(command_strings, list(
|
||||
paicard.pai.mind.transfer_to(src)
|
||||
to_chat(src, span_notice("You sense your form change as you are uploaded into [src]."))
|
||||
name = paicard.pai.name
|
||||
faction = user.faction.Copy()
|
||||
original_faction = get_faction()
|
||||
original_allies = allies
|
||||
SET_FACTION_AND_ALLIES_FROM(src, user)
|
||||
log_combat(user, paicard.pai, "uploaded to [initial(src.name)],")
|
||||
return TRUE
|
||||
|
||||
@@ -737,7 +743,8 @@ GLOBAL_LIST_INIT(command_strings, list(
|
||||
to_chat(paicard.pai, span_notice("You feel your control fade as [paicard] ejects from [initial(name)]."))
|
||||
paicard = null
|
||||
name = initial(name)
|
||||
faction = initial(faction)
|
||||
set_faction(original_faction)
|
||||
set_allies(original_allies)
|
||||
remove_all_languages(source = LANGUAGE_PAI)
|
||||
get_selected_language()
|
||||
|
||||
@@ -773,10 +780,9 @@ GLOBAL_LIST_INIT(command_strings, list(
|
||||
/mob/living/basic/bot/rust_heretic_act()
|
||||
adjust_brute_loss(400)
|
||||
|
||||
/mob/living/basic/bot/proc/attempt_access(mob/bot, obj/door_attempt)
|
||||
/mob/living/basic/bot/proc/retrieve_access(mob/bot, list/player_access)
|
||||
SIGNAL_HANDLER
|
||||
|
||||
return (door_attempt.check_access(access_card) ? ACCESS_ALLOWED : ACCESS_DISALLOWED)
|
||||
player_access += access_card.GetAccess()
|
||||
|
||||
/mob/living/basic/bot/proc/generate_speak_list()
|
||||
return null
|
||||
|
||||
@@ -161,9 +161,9 @@
|
||||
|
||||
/mob/living/basic/bot/cleanbot/Entered(atom/movable/arrived, atom/old_loc, list/atom/old_locs)
|
||||
. = ..()
|
||||
if(istype(arrived, /obj/item/reagent_containers/cup/bucket) && isnull(build_bucket))
|
||||
if(istype(arrived, /obj/item/reagent_containers/cup/bucket))
|
||||
QDEL_NULL(build_bucket)
|
||||
build_bucket = arrived
|
||||
return
|
||||
|
||||
if(istype(arrived, /obj/item/mop) && isnull(our_mop))
|
||||
our_mop = arrived
|
||||
@@ -208,7 +208,7 @@
|
||||
|
||||
/mob/living/basic/bot/cleanbot/explode()
|
||||
var/atom/drop_loc = drop_location()
|
||||
build_bucket.forceMove(drop_loc)
|
||||
build_bucket?.forceMove(drop_loc)
|
||||
new /obj/item/assembly/prox_sensor(drop_loc)
|
||||
if(weapon)
|
||||
weapon.force = initial(weapon.force)
|
||||
@@ -256,11 +256,6 @@
|
||||
GLOB.janitor_devices -= src
|
||||
return ..()
|
||||
|
||||
/mob/living/basic/bot/cleanbot/proc/apply_custom_bucket(obj/item/custom_bucket)
|
||||
if(!isnull(build_bucket))
|
||||
QDEL_NULL(build_bucket)
|
||||
custom_bucket.forceMove(src)
|
||||
|
||||
/mob/living/basic/bot/cleanbot/proc/on_attack_by(datum/source, obj/item/used_item, mob/living/user)
|
||||
SIGNAL_HANDLER
|
||||
if(!istype(used_item, /obj/item/knife) || user.combat_mode)
|
||||
|
||||
@@ -29,8 +29,6 @@
|
||||
|
||||
/datum/action/cooldown/mob_cooldown/bot/foam/Activate(mob/living/firer, atom/target)
|
||||
owner.visible_message(span_danger("[owner] whirs and bubbles violently, before releasing a plume of froth!"))
|
||||
var/datum/effect_system/fluid_spread/foam/foam = new
|
||||
foam.set_up(foam_range, holder = owner, location = owner.loc)
|
||||
foam.start()
|
||||
do_foam(foam_range, owner, owner.loc)
|
||||
StartCooldown()
|
||||
return TRUE
|
||||
|
||||
@@ -185,7 +185,7 @@
|
||||
continue
|
||||
if(!HAS_TRAIT(human_target, TRAIT_CLEANBOT_WHISPERER))
|
||||
continue
|
||||
if((living_pawn.faction.Find(REF(human_target))))
|
||||
if(living_pawn.has_ally(REF(human_target)))
|
||||
continue
|
||||
return human_target
|
||||
return null
|
||||
|
||||
@@ -109,7 +109,7 @@
|
||||
|
||||
/datum/action/cooldown/mob_cooldown/exenterate/proc/slash_em(atom/caster)
|
||||
for(var/mob/living/victim in range(ability_range, caster))
|
||||
if(faction_check(victim.faction, immune_factions) && victim.IsReachableBy(owner))
|
||||
if(victim.has_faction(immune_factions) && victim.IsReachableBy(owner))
|
||||
continue
|
||||
to_chat(caster, span_warning("You slice [victim]!"))
|
||||
to_chat(victim, span_warning("You are cut by [caster]'s blades!"))
|
||||
|
||||
@@ -134,9 +134,7 @@
|
||||
/mob/living/basic/bot/firebot/atmos_expose(datum/gas_mixture/air, exposed_temperature)
|
||||
if(!COOLDOWN_FINISHED(src, foam_cooldown))
|
||||
return
|
||||
var/datum/effect_system/fluid_spread/foam/firefighting/foam = new
|
||||
foam.set_up(3, holder = src, location = loc)
|
||||
foam.start()
|
||||
do_foam(3, src, loc, foam_type = /datum/effect_system/fluid_spread/foam/firefighting)
|
||||
COOLDOWN_START(src, foam_cooldown, FOAM_INTERVAL)
|
||||
|
||||
/mob/living/basic/bot/firebot/proc/spray_water(atom/attacked_atom, list/modifiers)
|
||||
|
||||
@@ -68,9 +68,7 @@
|
||||
RegisterSignal(src, COMSIG_HOSTILE_PRE_ATTACKINGTARGET, PROC_REF(on_attack))
|
||||
|
||||
/mob/living/basic/bot/hygienebot/explode()
|
||||
var/datum/effect_system/fluid_spread/foam/foam = new
|
||||
foam.set_up(2, holder = src, location = loc)
|
||||
foam.start()
|
||||
do_foam(2, src, loc)
|
||||
return ..()
|
||||
|
||||
/mob/living/basic/bot/hygienebot/generate_speak_list()
|
||||
|
||||
@@ -99,6 +99,8 @@
|
||||
var/skin = "generic"
|
||||
/// How much healing do we do at a time?
|
||||
var/heal_amount = 2.5
|
||||
/// How much healing multiplier do we have from upgrades?
|
||||
VAR_FINAL/heal_multiplier = 1.0
|
||||
/// Start healing when they have this much damage in a category
|
||||
var/heal_threshold = 10
|
||||
/// What damage type does this bot support. Because the default is brute, if the medkit is brute-oriented there is a slight bonus to healing. set to "all" for it to heal any of the 4 base damage types
|
||||
@@ -163,6 +165,13 @@
|
||||
if(!CONFIG_GET(flag/no_default_techweb_link) && !linked_techweb)
|
||||
CONNECT_TO_RND_SERVER_ROUNDSTART(linked_techweb, src)
|
||||
|
||||
if(linked_techweb)
|
||||
RegisterSignal(linked_techweb, COMSIG_TECHWEB_ADD_DESIGN, PROC_REF(on_techweb_research))
|
||||
RegisterSignal(linked_techweb, COMSIG_TECHWEB_REMOVE_DESIGN, PROC_REF(on_techweb_unresearch))
|
||||
|
||||
for(var/datum/design/medibot_upgrade/design in linked_techweb.get_researched_design_datums())
|
||||
heal_multiplier += design.additive_multiplier
|
||||
|
||||
/mob/living/basic/bot/medbot/on_craft_completion(list/components, datum/crafting_recipe/current_recipe, atom/crafter)
|
||||
. = ..()
|
||||
var/obj/item/storage/medkit/medkit = locate() in contents
|
||||
@@ -214,7 +223,6 @@
|
||||
data["custom_controls"]["speaker"] = medical_mode_flags & MEDBOT_SPEAK_MODE
|
||||
data["custom_controls"]["crit_alerts"] = medical_mode_flags & MEDBOT_DECLARE_CRIT
|
||||
data["custom_controls"]["stationary_mode"] = medical_mode_flags & MEDBOT_STATIONARY_MODE
|
||||
data["custom_controls"]["sync_tech"] = TRUE
|
||||
return data
|
||||
|
||||
// Actions received from TGUI
|
||||
@@ -237,21 +245,6 @@
|
||||
medical_mode_flags ^= MEDBOT_DECLARE_CRIT
|
||||
if("stationary_mode")
|
||||
medical_mode_flags ^= MEDBOT_STATIONARY_MODE
|
||||
if("sync_tech")
|
||||
if(!linked_techweb)
|
||||
to_chat(user, span_notice("No research techweb connected."))
|
||||
return
|
||||
var/oldheal_amount = heal_amount
|
||||
var/tech_boosters
|
||||
for(var/index in linked_techweb.researched_designs)
|
||||
var/datum/design/surgery/healing/design = SSresearch.techweb_design_by_id(index)
|
||||
if(!istype(design))
|
||||
continue
|
||||
tech_boosters++
|
||||
if(tech_boosters)
|
||||
heal_amount = (round(tech_boosters * 0.5, 0.1) * initial(heal_amount)) + initial(heal_amount) //every 2 tend wounds tech gives you an extra 100% healing, adjusting for unique branches (combo is bonus)
|
||||
if(oldheal_amount < heal_amount)
|
||||
speak("New knowledge found! Surgical efficacy improved to [round(heal_amount/initial(heal_amount)*100)]%!")
|
||||
|
||||
update_appearance()
|
||||
|
||||
@@ -347,7 +340,7 @@
|
||||
if(!do_after(src, delay = 2 SECONDS, target = patient, interaction_key = TEND_DAMAGE_INTERACTION))
|
||||
update_bot_mode(new_mode = BOT_IDLE)
|
||||
return
|
||||
var/modified_heal_amount = heal_amount
|
||||
var/modified_heal_amount = heal_amount * heal_multiplier
|
||||
var/done_healing = FALSE
|
||||
if(damage_type_healer == BRUTE && medkit_type == /obj/item/storage/medkit/brute)
|
||||
modified_heal_amount *= 1.1
|
||||
@@ -376,6 +369,24 @@
|
||||
if(patient.IsReachableBy(src))
|
||||
melee_attack(patient)
|
||||
|
||||
/mob/living/basic/bot/medbot/proc/on_techweb_research(datum/source, datum/design/medibot_upgrade/design)
|
||||
SIGNAL_HANDLER
|
||||
|
||||
if(!istype(design))
|
||||
return
|
||||
|
||||
heal_multiplier += design.additive_multiplier
|
||||
INVOKE_ASYNC(src, PROC_REF(speak), "New knowledge found! Surgical efficacy improved to [round(heal_multiplier * 100)]%!")
|
||||
|
||||
/mob/living/basic/bot/medbot/proc/on_techweb_unresearch(datum/source, datum/design/medibot_upgrade/design)
|
||||
SIGNAL_HANDLER
|
||||
|
||||
if(!istype(design))
|
||||
return
|
||||
|
||||
heal_multiplier -= design.additive_multiplier
|
||||
INVOKE_ASYNC(src, PROC_REF(speak), "Error! Surgical efficacy decreased to [round(heal_multiplier * 100)]%!")
|
||||
|
||||
/datum/id_trim/medibot
|
||||
assignment = JOB_MEDIBOT
|
||||
trim_state = "trim_paramedic"
|
||||
|
||||
@@ -42,6 +42,7 @@
|
||||
|
||||
/mob/living/basic/clown/Initialize(mapload)
|
||||
. = ..()
|
||||
ADD_TRAIT(src, TRAIT_NAIVE, INNATE_TRAIT)
|
||||
AddElement(/datum/element/footstep, footstep_type = FOOTSTEP_MOB_SHOE)
|
||||
AddComponent(/datum/component/ai_retaliate_advanced, CALLBACK(src, PROC_REF(retaliate_callback)))
|
||||
ai_controller.set_blackboard_key(BB_BASIC_MOB_SPEAK_LINES, emotes)
|
||||
@@ -148,7 +149,7 @@
|
||||
/obj/effect/gibspawner/human,
|
||||
/obj/item/clothing/mask/gas/clown_hat,
|
||||
/obj/item/food/meatclown,
|
||||
/obj/item/stack/sheet/animalhide/human,
|
||||
/obj/item/stack/sheet/animalhide/carbon/human,
|
||||
)
|
||||
emotes = list(
|
||||
BB_EMOTE_SAY = list(
|
||||
|
||||
@@ -180,7 +180,7 @@
|
||||
|
||||
/mob/living/basic/construct/harvester/heretic/grant_abilities()
|
||||
AddElement(/datum/element/wall_walker, or_trait = TRAIT_RUSTY)
|
||||
AddElement(/datum/element/leeching_walk)
|
||||
AddElement(/datum/element/rust_healing)
|
||||
AddComponent(\
|
||||
/datum/component/amputating_limbs,\
|
||||
surgery_time = 1.5 SECONDS,\
|
||||
@@ -206,7 +206,7 @@
|
||||
|
||||
// These aren't friends they're assholes
|
||||
// Don't let them be near you!
|
||||
/mob/living/basic/construct/harvester/heretic/Life(seconds_per_tick, times_fired)
|
||||
/mob/living/basic/construct/harvester/heretic/Life(seconds_per_tick)
|
||||
. = ..()
|
||||
if(!.) //dead or deleted
|
||||
return
|
||||
|
||||
@@ -53,7 +53,7 @@
|
||||
/mob/living/basic/vatbeast/tamed(mob/living/tamer, obj/item/food)
|
||||
buckle_lying = 0
|
||||
AddElement(/datum/element/ridable, /datum/component/riding/creature/vatbeast)
|
||||
faction = list(FACTION_NEUTRAL)
|
||||
set_faction(list(FACTION_NEUTRAL))
|
||||
|
||||
/mob/living/basic/vatbeast/proc/add_cell_sample()
|
||||
AddElement(/datum/element/swabable, CELL_LINE_TABLE_VATBEAST, CELL_VIRUS_TABLE_GENERIC_MOB, 1, 5)
|
||||
|
||||
@@ -34,6 +34,7 @@
|
||||
var/grow_as = /mob/living/basic/chicken
|
||||
|
||||
/datum/emote/chick
|
||||
abstract_type = /datum/emote/chick
|
||||
mob_type_allowed_typecache = /mob/living/basic/chick
|
||||
mob_type_blacklist_typecache = list()
|
||||
|
||||
|
||||
@@ -39,6 +39,7 @@ GLOBAL_VAR_INIT(chicken_count, 0)
|
||||
var/fertile = TRUE
|
||||
|
||||
/datum/emote/chicken
|
||||
abstract_type = /datum/emote/chicken
|
||||
mob_type_allowed_typecache = /mob/living/basic/chicken
|
||||
mob_type_blacklist_typecache = list()
|
||||
|
||||
|
||||
@@ -37,6 +37,7 @@
|
||||
var/milked_reagent = /datum/reagent/consumable/milk
|
||||
|
||||
/datum/emote/cow
|
||||
abstract_type = /datum/emote/cow
|
||||
mob_type_allowed_typecache = /mob/living/basic/cow
|
||||
mob_type_blacklist_typecache = list()
|
||||
|
||||
|
||||
@@ -37,7 +37,7 @@
|
||||
/mob/living/basic/cow/moonicorn/tamed(mob/living/tamer, atom/food)
|
||||
. = ..()
|
||||
///stop killing my FRIENDS
|
||||
faction |= tamer.faction
|
||||
APPLY_FACTION_AND_ALLIES_FROM(src, tamer)
|
||||
|
||||
/datum/ai_controller/basic_controller/cow/moonicorn
|
||||
blackboard = list(
|
||||
|
||||
@@ -44,7 +44,7 @@
|
||||
if(!stat && !user.combat_mode)
|
||||
to_chat(user, span_nicegreen("[src] whispers you some intense wisdoms and then disappears!"))
|
||||
user.mind?.adjust_experience(granted_wisdom, granted_experience)
|
||||
do_smoke(1, holder = src, location = get_turf(src))
|
||||
do_smoke(1, src, get_turf(src))
|
||||
qdel(src)
|
||||
return
|
||||
return ..()
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
/datum/emote/gorilla
|
||||
abstract_type = /datum/emote/gorilla
|
||||
mob_type_allowed_typecache = /mob/living/basic/gorilla
|
||||
mob_type_blacklist_typecache = list()
|
||||
|
||||
|
||||
@@ -29,6 +29,7 @@
|
||||
ai_controller = /datum/ai_controller/basic_controller/pig
|
||||
|
||||
/datum/emote/pig
|
||||
abstract_type = /datum/emote/pig
|
||||
mob_type_allowed_typecache = /mob/living/basic/pig
|
||||
mob_type_blacklist_typecache = list()
|
||||
|
||||
@@ -39,6 +40,7 @@
|
||||
emote_type = EMOTE_VISIBLE | EMOTE_AUDIBLE
|
||||
vary = TRUE
|
||||
sound = SFX_PIG_OINK
|
||||
|
||||
/mob/living/basic/pig/Initialize(mapload)
|
||||
. = ..()
|
||||
AddElement(/datum/element/pet_bonus, "oink")
|
||||
|
||||
@@ -34,6 +34,7 @@
|
||||
var/list/ponycolors = list("#cc8c5d", "#cc8c5d")
|
||||
|
||||
/datum/emote/pony
|
||||
abstract_type = /datum/emote/pony
|
||||
mob_type_allowed_typecache = /mob/living/basic/pony
|
||||
mob_type_blacklist_typecache = list()
|
||||
|
||||
|
||||
@@ -40,10 +40,11 @@
|
||||
var/icon_prefix = "rabbit"
|
||||
|
||||
/datum/emote/rabbit
|
||||
abstract_type = /datum/emote/rabbit
|
||||
mob_type_allowed_typecache = /mob/living/basic/rabbit
|
||||
mob_type_blacklist_typecache = list()
|
||||
|
||||
/datum/emote/rabbit
|
||||
/datum/emote/rabbit/hop
|
||||
key = "hop"
|
||||
key_third_person = "hops"
|
||||
message = "hops around happily!"
|
||||
|
||||
@@ -14,6 +14,7 @@
|
||||
gold_core_spawnable = HOSTILE_SPAWN
|
||||
basic_mob_flags = DEL_ON_DEATH
|
||||
status_flags = CANPUSH
|
||||
mob_biotypes = MOB_MINERAL
|
||||
|
||||
response_help_continuous = "rubs"
|
||||
response_help_simple = "rub"
|
||||
|
||||
@@ -15,7 +15,6 @@
|
||||
mob_biotypes = MOB_SPECIAL
|
||||
sentience_type = SENTIENCE_HUMANOID
|
||||
hud_type = /datum/hud/guardian
|
||||
faction = list()
|
||||
speed = 0
|
||||
status_flags = CANPUSH
|
||||
maxHealth = INFINITY // The spirit itself is invincible and passes damage to its host
|
||||
@@ -137,7 +136,7 @@
|
||||
/mob/living/basic/guardian/proc/guardian_recolour()
|
||||
if (isnull(client))
|
||||
return
|
||||
var/chosen_guardian_colour = tgui_color_picker(src, "What would you like your colour to be?", "Choose Your Colour", "#ffffff") // BUBBERSTATION EDIT: TGUI COLOR PICKER
|
||||
var/chosen_guardian_colour = tgui_color_picker(src, "What would you like your colour to be?", "Choose Your Colour", COLOR_WHITE)
|
||||
if (isnull(chosen_guardian_colour)) //redo proc until we get a color
|
||||
to_chat(src, span_warning("Invalid colour, please try again."))
|
||||
return guardian_recolour()
|
||||
@@ -200,7 +199,7 @@
|
||||
/mob/living/basic/guardian/gib()
|
||||
death(TRUE)
|
||||
|
||||
/mob/living/basic/guardian/dust(just_ash, drop_items, force)
|
||||
/mob/living/basic/guardian/dust(just_ash, drop_items, give_moodlet, force)
|
||||
death(TRUE)
|
||||
|
||||
/// Link up with a summoner mob.
|
||||
@@ -225,8 +224,9 @@
|
||||
if (mind)
|
||||
mind.enslave_mind_to_creator(to_who)
|
||||
else //mindless guardian, manually give them factions
|
||||
faction += summoner.faction
|
||||
summoner.faction += "[REF(src)]"
|
||||
add_faction(summoner.get_faction())
|
||||
add_ally(summoner.allies)
|
||||
summoner.add_ally(src)
|
||||
remove_all_languages(LANGUAGE_MASTER)
|
||||
copy_languages(to_who, LANGUAGE_MASTER) // make sure holoparasites speak same language as master
|
||||
RegisterSignal(to_who, COMSIG_QDELETING, PROC_REF(on_summoner_deletion))
|
||||
@@ -251,8 +251,8 @@
|
||||
unleash()
|
||||
UnregisterSignal(summoner, list(COMSIG_QDELETING, COMSIG_LIVING_ON_WABBAJACKED, COMSIG_LIVING_SHAPESHIFTED, COMSIG_LIVING_UNSHAPESHIFTED))
|
||||
if (different_person)
|
||||
summoner.faction -= "[REF(src)]"
|
||||
faction -= summoner.faction
|
||||
summoner.remove_ally(src)
|
||||
remove_faction(summoner.get_faction())
|
||||
mind?.remove_all_antag_datums()
|
||||
if (!length(summoner.get_all_linked_holoparasites() - src))
|
||||
for (var/action_type in control_actions)
|
||||
|
||||
@@ -135,6 +135,7 @@ GLOBAL_LIST_INIT(guardian_radial_images, setup_guardian_radial())
|
||||
to_chat(user, guardian_theme.get_fluff_string(summoned_guardian.guardian_type))
|
||||
to_chat(user, replacetext(success_message, "%GUARDIAN", mob_name))
|
||||
summoned_guardian.client?.init_verbs()
|
||||
summoned_guardian.updatehealth() // Set the initial health hud
|
||||
return summoned_guardian
|
||||
|
||||
/// Checks to ensure we're still capable of using the radial selector
|
||||
|
||||
@@ -30,9 +30,14 @@
|
||||
return
|
||||
. += span_info("It is holding [internal_storage.examine_title(user)] in its internal storage.")
|
||||
|
||||
/mob/living/basic/guardian/dextrous/manifest_effects()
|
||||
. = ..()
|
||||
REMOVE_TRAIT(src, TRAIT_HANDS_BLOCKED, GUARDIAN_RECALLED)
|
||||
|
||||
/mob/living/basic/guardian/dextrous/recall_effects()
|
||||
. = ..()
|
||||
drop_all_held_items()
|
||||
ADD_TRAIT(src, TRAIT_HANDS_BLOCKED, GUARDIAN_RECALLED)
|
||||
|
||||
// Bullshit related to having a fake pocket begins here
|
||||
|
||||
|
||||
@@ -48,7 +48,7 @@
|
||||
source.set_fire_stacks(0, remove_wet_stacks = FALSE)
|
||||
|
||||
/// Maintain our summoner at a stable body temperature
|
||||
/mob/living/basic/guardian/gaseous/proc/on_summoner_life(mob/living/source, seconds_per_tick, times_fired)
|
||||
/mob/living/basic/guardian/gaseous/proc/on_summoner_life(mob/living/source, seconds_per_tick)
|
||||
SIGNAL_HANDLER
|
||||
source.adjust_bodytemperature(get_temp_change_amount((summoner.get_body_temp_normal() - summoner.bodytemperature), temp_stabilization_rate * seconds_per_tick))
|
||||
|
||||
@@ -82,6 +82,8 @@
|
||||
button_icon_state = "smoke"
|
||||
cooldown_time = 0 SECONDS // We're here for the interface not the cooldown
|
||||
click_to_activate = FALSE
|
||||
/// Particle effect we use to show smoke
|
||||
VAR_PRIVATE/obj/effect/abstract/particle_holder/mob_smoke
|
||||
/// Gas being expelled.
|
||||
var/active_gas = null
|
||||
/// Associative list of types of gases to moles we create every life tick.
|
||||
@@ -132,13 +134,10 @@
|
||||
owner.investigate_log("set their gas type to [picked_gas].", INVESTIGATE_ATMOS)
|
||||
var/had_gas = !isnull(active_gas)
|
||||
active_gas = gas_type
|
||||
if(isnull(owner.particles))
|
||||
owner.particles = new /particles/smoke/steam()
|
||||
owner.particles.position = list(-1, 8, 0)
|
||||
owner.particles.fadein = 5
|
||||
owner.particles.height = 200
|
||||
if(isnull(mob_smoke))
|
||||
mob_smoke = new(owner, /particles/smoke/steam/guardian)
|
||||
var/datum/gas/chosen_gas = active_gas // Casting it so that we can access gas vars in initial, it's still a typepath
|
||||
owner.particles.color = initial(chosen_gas.primary_color)
|
||||
mob_smoke.color = initial(chosen_gas.primary_color)
|
||||
if (!had_gas)
|
||||
RegisterSignal(owner, COMSIG_LIVING_LIFE, PROC_REF(on_life))
|
||||
|
||||
@@ -148,11 +147,11 @@
|
||||
if (!isnull(active_gas))
|
||||
to_chat(src, span_notice("You stop releasing gas."))
|
||||
active_gas = null
|
||||
QDEL_NULL(owner.particles)
|
||||
QDEL_NULL(mob_smoke)
|
||||
UnregisterSignal(owner, COMSIG_LIVING_LIFE)
|
||||
|
||||
/// Release gas every life tick while active
|
||||
/datum/action/cooldown/mob_cooldown/expel_gas/proc/on_life(datum/source, seconds_per_tick, times_fired)
|
||||
/datum/action/cooldown/mob_cooldown/expel_gas/proc/on_life(datum/source, seconds_per_tick)
|
||||
SIGNAL_HANDLER
|
||||
if (isnull(active_gas))
|
||||
return // We shouldn't even be registered at this point but just in case
|
||||
|
||||
@@ -71,7 +71,9 @@
|
||||
/// Overlay for our protection shield.
|
||||
var/mutable_appearance/shield_overlay
|
||||
/// Damage coefficients when shielded
|
||||
var/list/shielded_damage = list(BRUTE = 0.05, BURN = 0.05, TOX = 0.05, STAMINA = 0, OXY = 0.05)
|
||||
var/static/list/shielded_damage = list(BRUTE = 0.05, BURN = 0.05, TOX = 0.05, STAMINA = 0, OXY = 0.05)
|
||||
// What the damage coefficients were previously
|
||||
var/list/original_damage_coeff
|
||||
|
||||
/datum/status_effect/protector_shield/on_apply()
|
||||
if (isguardian(owner))
|
||||
@@ -86,6 +88,7 @@
|
||||
|
||||
if (isbasicmob(owner)) // Better hope you are or this status is doing basically nothing useful for you
|
||||
var/mob/living/basic/basic_owner = owner
|
||||
original_damage_coeff = basic_owner.damage_coeff
|
||||
basic_owner.damage_coeff = shielded_damage
|
||||
|
||||
to_chat(owner, span_bolddanger("You enter protection mode."))
|
||||
@@ -101,7 +104,7 @@
|
||||
|
||||
if (isbasicmob(owner))
|
||||
var/mob/living/basic/basic_owner = owner
|
||||
basic_owner.damage_coeff = initial(basic_owner.damage_coeff)
|
||||
basic_owner.damage_coeff = original_damage_coeff
|
||||
|
||||
to_chat(owner, span_bolddanger("You return to your normal mode."))
|
||||
UnregisterSignal(owner, list(COMSIG_ATOM_UPDATE_OVERLAYS) + COMSIG_LIVING_ADJUST_STANDARD_DAMAGE_TYPES)
|
||||
|
||||
@@ -24,6 +24,7 @@
|
||||
action_text = "",\
|
||||
complete_text = "",\
|
||||
required_modifier = RIGHT_CLICK,\
|
||||
extra_checks = CALLBACK(src, PROC_REF(is_deployed)),\
|
||||
after_healed = CALLBACK(src, PROC_REF(after_healed)),\
|
||||
)
|
||||
|
||||
|
||||
@@ -21,6 +21,6 @@
|
||||
)
|
||||
grant_actions_by_list(actions_to_add)
|
||||
|
||||
/mob/living/basic/heretic_summon/ash_spirit/Life(seconds_per_tick, times_fired)
|
||||
/mob/living/basic/heretic_summon/ash_spirit/Life(seconds_per_tick)
|
||||
. = ..()
|
||||
adjust_brute_loss(-3) // 3 health passively healing
|
||||
|
||||
@@ -15,6 +15,7 @@
|
||||
maxHealth = 65
|
||||
health = 65
|
||||
sight = SEE_MOBS|SEE_OBJS|SEE_TURFS
|
||||
mob_biotypes = MOB_ORGANIC
|
||||
/// List of innate abilities we have to add.
|
||||
var/static/list/innate_abilities = list(
|
||||
/datum/action/cooldown/spell/jaunt/ethereal_jaunt/ash/long = null,
|
||||
|
||||
@@ -13,6 +13,7 @@
|
||||
sight = SEE_TURFS
|
||||
speed = 1
|
||||
ai_controller = /datum/ai_controller/basic_controller/rust_walker
|
||||
mob_biotypes = MOB_ROBOTIC|MOB_MINERAL
|
||||
|
||||
/mob/living/basic/heretic_summon/rust_walker/Initialize(mapload)
|
||||
. = ..()
|
||||
@@ -28,6 +29,9 @@
|
||||
. = ..()
|
||||
update_appearance(UPDATE_ICON_STATE)
|
||||
|
||||
/mob/living/basic/heretic_summon/rust_walker/do_rust_heretic_act(atom/target)
|
||||
target.rust_heretic_act(RUST_RESISTANCE_TITANIUM)
|
||||
|
||||
/mob/living/basic/heretic_summon/rust_walker/update_icon_state()
|
||||
. = ..()
|
||||
if(stat == DEAD) // We usually delete on death but just in case
|
||||
@@ -38,7 +42,7 @@
|
||||
icon_state = "[base_icon_state]_s"
|
||||
icon_living = icon_state
|
||||
|
||||
/mob/living/basic/heretic_summon/rust_walker/Life(seconds_per_tick = SSMOBS_DT, times_fired)
|
||||
/mob/living/basic/heretic_summon/rust_walker/Life(seconds_per_tick = SSMOBS_DT)
|
||||
. = ..()
|
||||
if(!.) //dead or deleted
|
||||
return
|
||||
|
||||
@@ -7,6 +7,7 @@
|
||||
icon_gib = "syndicate_gib"
|
||||
mouse_opacity = MOUSE_OPACITY_ICON
|
||||
basic_mob_flags = DEL_ON_DEATH
|
||||
mob_biotypes = MOB_ORGANIC|MOB_MINERAL|MOB_MINING
|
||||
speed = 2
|
||||
maxHealth = 150
|
||||
health = 150
|
||||
|
||||
@@ -83,5 +83,5 @@
|
||||
. = ..()
|
||||
if(isnull(.))
|
||||
return
|
||||
faction = new_friend.faction.Copy()
|
||||
SET_FACTION_AND_ALLIES_FROM(src, new_friend)
|
||||
visible_message(span_notice("[src] lowers [src.p_their()] snout at [new_friend]'s offering and begins to wag [src.p_their()] tail."))
|
||||
|
||||
@@ -50,9 +50,11 @@
|
||||
try_replicate()
|
||||
|
||||
/// Full setup for illusion mobs to lessen code duplication in the individual files.
|
||||
/mob/living/basic/illusion/proc/full_setup(mob/living/original, mob/living/target_mob = null, list/faction = null, life = 5 SECONDS, hp = 100, damage = 0, replicate = 0)
|
||||
/mob/living/basic/illusion/proc/full_setup(mob/living/original, mob/living/target_mob = null, list/faction_override = null, life = 5 SECONDS, hp = 100, damage = 0, replicate = 0)
|
||||
mock_as(original, life, hp, damage, replicate)
|
||||
set_faction(faction)
|
||||
SET_FACTION_AND_ALLIES_FROM(src, original)
|
||||
if(faction_override)
|
||||
set_faction(faction_override)
|
||||
set_target(target_mob)
|
||||
|
||||
/// Gives the illusion a target to focus on in whatever behavior it wants to engage as.
|
||||
@@ -61,12 +63,6 @@
|
||||
return
|
||||
ai_controller.set_blackboard_key(target_key, target_mob)
|
||||
|
||||
/// Sets the faction of the illusion
|
||||
/mob/living/basic/illusion/proc/set_faction(list/new_faction)
|
||||
if(!new_faction) // can be list with no length or null
|
||||
return
|
||||
faction = new_faction.Copy()
|
||||
|
||||
/// Does the actual work of setting up the illusion's appearance and some other functionality.
|
||||
/mob/living/basic/illusion/proc/mock_as(mob/living/original, life, hp, damage, replicate)
|
||||
if(QDELETED(original))
|
||||
@@ -83,7 +79,7 @@
|
||||
melee_damage_upper = damage
|
||||
multiply_chance = replicate
|
||||
|
||||
faction -= FACTION_NEUTRAL
|
||||
remove_faction(FACTION_NEUTRAL)
|
||||
transform = initial(transform)
|
||||
pixel_x = base_pixel_x
|
||||
pixel_y = base_pixel_y
|
||||
@@ -104,7 +100,7 @@
|
||||
new_clone.full_setup(
|
||||
parent_mob,
|
||||
target_mob = ai_controller.blackboard[target_key],
|
||||
faction = faction,
|
||||
faction_override = faction,
|
||||
life = 8 SECONDS,
|
||||
hp = health / 2,
|
||||
damage = melee_damage_upper,
|
||||
|
||||
@@ -62,11 +62,11 @@
|
||||
taste_description = "french cuisine"
|
||||
taste_mult = 1.3
|
||||
|
||||
/datum/reagent/toxin/leaper_venom/on_mob_life(mob/living/carbon/poisoned_mob, seconds_per_tick, times_fired)
|
||||
/datum/reagent/toxin/leaper_venom/on_mob_life(mob/living/carbon/poisoned_mob, seconds_per_tick, metabolization_ratio)
|
||||
. = ..()
|
||||
if(volume <= 5)
|
||||
return
|
||||
if(poisoned_mob.adjust_tox_loss(2.5 * REM * seconds_per_tick, updating_health = FALSE))
|
||||
if(poisoned_mob.adjust_tox_loss(1.25 * metabolization_ratio * seconds_per_tick, updating_health = FALSE))
|
||||
return UPDATE_MOB_HEALTH
|
||||
|
||||
// bubble ability structure
|
||||
@@ -247,4 +247,4 @@
|
||||
/datum/action/cooldown/spell/conjure/limit_summons/create_suicide_toads/post_summon(atom/summoned_object, atom/cast_on)
|
||||
. = ..()
|
||||
var/mob/living/summoned_toad = summoned_object
|
||||
summoned_toad.faction = owner.faction ///so they dont attack the leaper or the wizard master
|
||||
SET_FACTION_AND_ALLIES_FROM(summoned_toad, owner) // so they dont attack the leaper or the wizard master
|
||||
|
||||
@@ -16,7 +16,7 @@
|
||||
return ..()
|
||||
|
||||
var/mob/living/living_target = target
|
||||
if(FACTION_JUNGLE in living_target.faction)
|
||||
if(living_target.has_faction(FACTION_JUNGLE))
|
||||
return BULLET_ACT_BLOCK
|
||||
|
||||
return ..()
|
||||
|
||||
@@ -185,7 +185,7 @@
|
||||
return
|
||||
tangle_ability.Trigger(target = victim)
|
||||
|
||||
/mob/living/basic/venus_human_trap/Life(seconds_per_tick = SSMOBS_DT, times_fired)
|
||||
/mob/living/basic/venus_human_trap/Life(seconds_per_tick = SSMOBS_DT)
|
||||
. = ..()
|
||||
if(!.)
|
||||
return FALSE
|
||||
|
||||
@@ -7,6 +7,7 @@
|
||||
icon_dead = "basilisk_dead"
|
||||
speak_emote = list("chimes")
|
||||
damage_coeff = list(BRUTE = 1, BURN = 0.1, TOX = 1, STAMINA = 0, OXY = 1)
|
||||
mob_biotypes = parent_type::mob_biotypes | MOB_MINERAL
|
||||
speed = 20
|
||||
maxHealth = 200
|
||||
health = 200
|
||||
|
||||
@@ -96,7 +96,7 @@
|
||||
. += span_info("Someone appears to have attached a saddle to this one.")
|
||||
|
||||
// Goliaths can summon tentacles more frequently as they take damage, scary.
|
||||
/mob/living/basic/mining/goliath/apply_damage(damage, damagetype, def_zone, blocked, forced, spread_damage, wound_bonus, exposed_wound_bonus, sharpness, attack_direction, attacking_item)
|
||||
/mob/living/basic/mining/goliath/apply_damage(damage, damagetype, def_zone, blocked, forced, spread_damage, wound_bonus, exposed_wound_bonus, sharpness, attack_direction, attacking_item, wound_clothing)
|
||||
. = ..()
|
||||
if (. <= 0)
|
||||
return
|
||||
@@ -159,7 +159,7 @@
|
||||
. = ..()
|
||||
if(isnull(.))
|
||||
return
|
||||
faction = new_friend.faction.Copy()
|
||||
SET_FACTION_AND_ALLIES_FROM(src, new_friend)
|
||||
|
||||
/mob/living/basic/mining/goliath/RangedAttack(atom/atom_target, modifiers)
|
||||
tentacles?.Trigger(target = atom_target)
|
||||
@@ -209,7 +209,7 @@
|
||||
/// List of places we might spawn a tentacle, if we're alive
|
||||
var/list/tentacle_target_turfs
|
||||
|
||||
/mob/living/basic/mining/goliath/ancient/immortal/Life(seconds_per_tick, times_fired)
|
||||
/mob/living/basic/mining/goliath/ancient/immortal/Life(seconds_per_tick)
|
||||
. = ..()
|
||||
if (!. || !isturf(loc))
|
||||
return
|
||||
|
||||
@@ -42,7 +42,7 @@
|
||||
for(var/mob/living/potential_friend in oview(9, living_pawn))
|
||||
if(!isashwalker(potential_friend))
|
||||
continue
|
||||
if((living_pawn.faction.Find(REF(potential_friend))))
|
||||
if(living_pawn.has_ally(REF(potential_friend)))
|
||||
continue
|
||||
living_pawn.befriend(potential_friend)
|
||||
to_chat(potential_friend, span_nicegreen("[living_pawn] looks at you with endearing eyes!"))
|
||||
|
||||
@@ -59,7 +59,7 @@
|
||||
/// Spawns a worm on the specified turf
|
||||
/mob/living/basic/mining/hivelord/proc/complete_spawn(turf/spawn_turf)
|
||||
var/mob/living/brood = new death_spawn_type(spawn_turf)
|
||||
brood.faction = faction
|
||||
SET_FACTION_AND_ALLIES_FROM(brood, src)
|
||||
brood.ai_controller?.set_blackboard_key(ai_controller.blackboard[BB_BASIC_MOB_CURRENT_TARGET])
|
||||
brood.dir = get_dir(src, spawn_turf)
|
||||
|
||||
|
||||
@@ -79,7 +79,7 @@
|
||||
/// Actually create a mob
|
||||
/datum/action/cooldown/mob_cooldown/hivelord_spawn/proc/complete_spawn(turf/spawn_turf, target)
|
||||
var/mob/living/brood = new spawn_type(spawn_turf)
|
||||
brood.faction = owner.faction
|
||||
SET_FACTION_AND_ALLIES_FROM(brood, owner)
|
||||
brood.ai_controller?.set_blackboard_key(ai_target_key, target)
|
||||
brood.dir = get_dir(owner, spawn_turf)
|
||||
|
||||
|
||||
@@ -85,7 +85,7 @@
|
||||
var/spawn_type = get_legion_type(target)
|
||||
var/mob/living/basic/mining/legion/new_legion = new spawn_type(loc)
|
||||
new_legion.consume(target)
|
||||
new_legion.faction = faction.Copy()
|
||||
new_legion.set_faction(get_faction())
|
||||
qdel(src)
|
||||
|
||||
/// Returns the kind of legion we make out of the target
|
||||
@@ -99,9 +99,9 @@
|
||||
/// Sets someone as our creator, mostly so you can't use skulls to heal yourself
|
||||
/mob/living/basic/mining/legion_brood/proc/assign_creator(mob/living/creator, copy_full_faction = TRUE)
|
||||
if (copy_full_faction)
|
||||
faction = creator.faction.Copy()
|
||||
set_faction(creator.get_faction())
|
||||
else
|
||||
faction |= REF(creator)
|
||||
add_ally(creator)
|
||||
created_by = WEAKREF(creator)
|
||||
ai_controller?.set_blackboard_key(BB_LEGION_BROOD_CREATOR, creator)
|
||||
RegisterSignal(creator, COMSIG_QDELETING, PROC_REF(creator_destroyed))
|
||||
|
||||
@@ -86,7 +86,7 @@
|
||||
skull.melee_attack(target)
|
||||
return TRUE
|
||||
|
||||
/obj/item/organ/legion_tumour/on_life(seconds_per_tick, times_fired)
|
||||
/obj/item/organ/legion_tumour/on_life(seconds_per_tick)
|
||||
. = ..()
|
||||
if (QDELETED(src) || QDELETED(owner))
|
||||
return
|
||||
|
||||
@@ -97,8 +97,8 @@
|
||||
. = ..()
|
||||
if(isnull(.))
|
||||
return
|
||||
faction |= new_friend.faction
|
||||
faction -= FACTION_MINING
|
||||
APPLY_FACTION_AND_ALLIES_FROM(src, new_friend)
|
||||
remove_faction(FACTION_MINING)
|
||||
|
||||
/mob/living/basic/mining/lobstrosity/mind_initialize()
|
||||
. = ..()
|
||||
@@ -171,6 +171,7 @@
|
||||
var/was_tamed = FALSE
|
||||
|
||||
/datum/emote/lobstrosity_juvenile
|
||||
abstract_type = /datum/emote/lobstrosity_juvenile
|
||||
mob_type_allowed_typecache = /mob/living/basic/mining/lobstrosity/juvenile
|
||||
mob_type_blacklist_typecache = list()
|
||||
|
||||
|
||||
@@ -58,6 +58,6 @@
|
||||
/mob/living/basic/mining/proc/check_ashwalker_peace_violation(datum/source, mob/living/carbon/human/possible_ashwalker)
|
||||
SIGNAL_HANDLER
|
||||
|
||||
if(!isashwalker(possible_ashwalker) || !(FACTION_ASHWALKER in faction))
|
||||
if(!isashwalker(possible_ashwalker) || !has_faction(FACTION_ASHWALKER))
|
||||
return
|
||||
faction.Remove(FACTION_ASHWALKER)
|
||||
remove_faction(FACTION_ASHWALKER)
|
||||
|
||||
@@ -31,7 +31,7 @@ GLOBAL_LIST_INIT(mook_commands, list(
|
||||
|
||||
///check for faction if not a ash walker, otherwise just attack
|
||||
/datum/targeting_strategy/basic/mook/faction_check(datum/ai_controller/controller, mob/living/living_mob, mob/living/the_target)
|
||||
if(FACTION_ASHWALKER in living_mob.faction)
|
||||
if(living_mob.has_faction(FACTION_ASHWALKER))
|
||||
return FALSE
|
||||
|
||||
return ..()
|
||||
|
||||
@@ -176,7 +176,7 @@ GLOBAL_LIST_EMPTY(raptor_population)
|
||||
if (0.8 to 0.999)
|
||||
. += span_notice("[p_They()] [p_have()] a few minor bruises and scratches.")
|
||||
|
||||
/mob/living/basic/raptor/Life(seconds_per_tick, times_fired)
|
||||
/mob/living/basic/raptor/Life(seconds_per_tick)
|
||||
. = ..()
|
||||
if (growth_stage != RAPTOR_BABY || HAS_TRAIT(src, TRAIT_STASIS) || stat == DEAD)
|
||||
return
|
||||
@@ -280,7 +280,7 @@ GLOBAL_LIST_EMPTY(raptor_population)
|
||||
return partner.raptor_color.guaranteed_crossbreeds[raptor_color.type]
|
||||
|
||||
// We've got all the colors in our family tree and aren't rolling a guarantee, bingo
|
||||
if (length(inherited_stats.parent_colors | partner.inherited_stats.parent_colors | raptor_color.type | partner.raptor_color.type) == length(GLOB.raptor_colors))
|
||||
if (length(inherited_stats.parent_colors | partner.inherited_stats.parent_colors | raptor_color.type | partner.raptor_color.type) >= (length(GLOB.raptor_colors) - 1))
|
||||
return /datum/raptor_color/black
|
||||
|
||||
var/list/prob_list = list()
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/obj/item/raptor_dex
|
||||
name = "RaptorDex"
|
||||
name = "\improper RaptorDex"
|
||||
desc = "A device used to analyze lavaland raptors!"
|
||||
icon = 'icons/obj/devices/scanner.dmi'
|
||||
icon_state = "raptor_dex"
|
||||
@@ -32,6 +32,8 @@
|
||||
scan_data["raptor_speed"] = my_raptor.speed + intent_mod?.multiplicative_slowdown
|
||||
scan_data["raptor_color"] = my_raptor.name
|
||||
scan_data["raptor_gender"] = my_raptor.gender
|
||||
scan_data["raptor_growth"] = my_raptor.growth_progress
|
||||
scan_data["can_grow"] = my_raptor.growth_stage != RAPTOR_ADULT
|
||||
scan_data["raptor_description"] = my_raptor.raptor_color.description
|
||||
|
||||
var/happiness_percentage = my_raptor.ai_controller?.blackboard[BB_BASIC_HAPPINESS]
|
||||
|
||||
@@ -276,4 +276,4 @@
|
||||
if(isnull(required_access))
|
||||
var/datum/id_trim/access_card = SSid_access.trim_singletons_by_path[/datum/id_trim/job/shaft_miner]
|
||||
required_access = access_card.access
|
||||
AddElement(/datum/element/mob_access, required_access)
|
||||
AddComponent(/datum/component/simple_access, required_access)
|
||||
|
||||
@@ -116,7 +116,7 @@
|
||||
if(isgroundlessturf(my_turf))
|
||||
return FALSE
|
||||
var/obj/effect/mine/minebot/my_mine = new(my_turf)
|
||||
my_mine.ignore_list = owner.faction.Copy()
|
||||
my_mine.ignore_list = owner.get_faction()
|
||||
playsound(my_turf, 'sound/items/weapons/armbomb.ogg', 20)
|
||||
StartCooldown()
|
||||
return TRUE
|
||||
@@ -153,9 +153,7 @@
|
||||
|
||||
/obj/effect/temp_visual/falling_rocket/proc/create_explosion()
|
||||
playsound(src, 'sound/items/weapons/minebot_rocket.ogg', 100, FALSE)
|
||||
var/datum/effect_system/fluid_spread/smoke/smoke = new
|
||||
smoke.set_up(1, holder = src)
|
||||
smoke.start()
|
||||
do_smoke(1, src, loc)
|
||||
for(var/mob/living/living_target in oview(explosion_radius, src))
|
||||
if(living_target.incorporeal_move)
|
||||
continue
|
||||
@@ -171,9 +169,7 @@
|
||||
/obj/effect/mine/minebot/mineEffect(mob/living/victim)
|
||||
if(!istype(victim))
|
||||
return
|
||||
var/datum/effect_system/fluid_spread/smoke/smoke = new
|
||||
smoke.set_up(0, holder = src)
|
||||
smoke.start()
|
||||
do_smoke(0, src, loc)
|
||||
playsound(src, 'sound/effects/explosion/explosion3.ogg', 100)
|
||||
victim.apply_damage(damage_to_apply)
|
||||
|
||||
@@ -183,6 +179,6 @@
|
||||
if(!isliving(on_who))
|
||||
return ..()
|
||||
var/mob/living/stepped_mob = on_who
|
||||
if(FACTION_NEUTRAL in stepped_mob.faction)
|
||||
if(stepped_mob.has_faction(FACTION_NEUTRAL))
|
||||
return FALSE
|
||||
return ..()
|
||||
|
||||
@@ -74,7 +74,7 @@
|
||||
controller.queue_behavior(/datum/ai_behavior/find_and_set, BB_DRONE_DEFEND, /mob/living/basic/node_drone)
|
||||
return
|
||||
var/mob/living/living_pawn = controller.pawn
|
||||
if(!living_pawn.faction.Find(REF(target)))
|
||||
if(!living_pawn.has_ally(target))
|
||||
controller.queue_behavior(/datum/ai_behavior/befriend_target, BB_DRONE_DEFEND)
|
||||
return
|
||||
if(target.health < (target.maxHealth * 0.75) && controller.blackboard[BB_MINEBOT_REPAIR_DRONE])
|
||||
|
||||
@@ -63,6 +63,7 @@
|
||||
var/datum/callback/post_birth_callback
|
||||
|
||||
/datum/emote/cat
|
||||
abstract_type = /datum/emote/cat
|
||||
mob_type_allowed_typecache = /mob/living/basic/pet/cat
|
||||
mob_type_blacklist_typecache = list()
|
||||
|
||||
|
||||
@@ -53,6 +53,7 @@
|
||||
var/cult_icon_state
|
||||
|
||||
/datum/emote/dog
|
||||
abstract_type = /datum/emote/dog
|
||||
mob_type_allowed_typecache = /mob/living/basic/pet/dog
|
||||
mob_type_blacklist_typecache = list()
|
||||
|
||||
|
||||
@@ -35,7 +35,7 @@
|
||||
update_appearance()
|
||||
AddElement(/datum/element/strippable, length(strippable_inventory_slots) ? create_strippable_list(strippable_inventory_slots) : GLOB.strippable_corgi_items)
|
||||
AddElement(/datum/element/swabable, CELL_LINE_TABLE_CORGI, CELL_VIRUS_TABLE_GENERIC_MOB, 1, 5)
|
||||
RegisterSignal(src, COMSIG_MOB_TRIED_ACCESS, PROC_REF(on_tried_access))
|
||||
RegisterSignal(src, COMSIG_MOB_RETRIEVE_ACCESS, PROC_REF(retrieve_access))
|
||||
RegisterSignals(src, list(COMSIG_BASICMOB_LOOK_ALIVE, COMSIG_BASICMOB_LOOK_DEAD), PROC_REF(on_appearance_change))
|
||||
if(can_breed)
|
||||
add_breeding_component()
|
||||
@@ -267,10 +267,10 @@
|
||||
var/datum/dog_fashion/equipped_back_fashion_item = new inventory_back.dog_fashion(src)
|
||||
equipped_back_fashion_item.apply(src)
|
||||
|
||||
///Handler for COMSIG_MOB_TRIED_ACCESS
|
||||
/mob/living/basic/pet/dog/corgi/proc/on_tried_access(mob/accessor, obj/locked_thing)
|
||||
///Handler for COMSIG_MOB_RETRIEVE_ACCESS
|
||||
/mob/living/basic/pet/dog/corgi/proc/retrieve_access(mob/accessor, list/player_access)
|
||||
SIGNAL_HANDLER
|
||||
return locked_thing?.check_access(access_card) ? ACCESS_ALLOWED : ACCESS_DISALLOWED
|
||||
player_access += access_card.GetAccess()
|
||||
|
||||
///Handles updating any existing overlays for the corgi (such as fashion items) when it changes how it appears, as in, dead or alive.
|
||||
/mob/living/basic/pet/dog/corgi/proc/on_appearance_change()
|
||||
|
||||
@@ -117,7 +117,7 @@
|
||||
name = new_name
|
||||
real_name = new_name
|
||||
|
||||
/mob/living/basic/pet/dog/breaddog/Life(seconds_per_tick = SSMOBS_DT, times_fired)
|
||||
/mob/living/basic/pet/dog/breaddog/Life(seconds_per_tick = SSMOBS_DT)
|
||||
. = ..()
|
||||
if(!.) //dead or deleted
|
||||
return
|
||||
|
||||
@@ -39,6 +39,7 @@
|
||||
)
|
||||
|
||||
/datum/emote/fox
|
||||
abstract_type = /datum/emote/fox
|
||||
mob_type_allowed_typecache = /mob/living/basic/pet/fox
|
||||
mob_type_blacklist_typecache = list()
|
||||
|
||||
|
||||
@@ -51,13 +51,13 @@
|
||||
else
|
||||
. += span_notice("It looks like it has already made its delivery.")
|
||||
|
||||
/mob/living/basic/pet/gondola/gondolapod/setOpened()
|
||||
/mob/living/basic/pet/gondola/gondolapod/set_opened()
|
||||
opened = TRUE
|
||||
layer = initial(layer)
|
||||
update_appearance()
|
||||
addtimer(CALLBACK(src, TYPE_PROC_REF(/atom/, setClosed)), 5 SECONDS)
|
||||
addtimer(CALLBACK(src, TYPE_PROC_REF(/atom/, set_closed)), 5 SECONDS)
|
||||
|
||||
/mob/living/basic/pet/gondola/gondolapod/setClosed()
|
||||
/mob/living/basic/pet/gondola/gondolapod/set_closed()
|
||||
opened = FALSE
|
||||
layer = LOW_MOB_LAYER
|
||||
update_appearance()
|
||||
|
||||
@@ -57,7 +57,7 @@
|
||||
return potential_victim
|
||||
if(!ishuman(potential_victim))
|
||||
continue
|
||||
if(living_pawn.faction.Find(REF(potential_victim)))
|
||||
if(living_pawn.has_ally(potential_victim))
|
||||
continue //dont steal from friends
|
||||
if(holding_valuable(controller, potential_victim))
|
||||
controller.set_blackboard_key(BB_ALWAYS_IGNORE_FACTION, TRUE)
|
||||
|
||||
@@ -20,6 +20,7 @@
|
||||
var/obj/carried_egg
|
||||
|
||||
/datum/emote/penguin
|
||||
abstract_type = /datum/emote/penguin
|
||||
mob_type_allowed_typecache = /mob/living/basic/pet/penguin
|
||||
mob_type_blacklist_typecache = list()
|
||||
|
||||
|
||||
@@ -51,7 +51,7 @@
|
||||
/datum/ai_behavior/find_and_set/friendly_cultist/search_tactic(datum/ai_controller/controller, locate_path, search_range = SEARCH_TACTIC_DEFAULT_RANGE)
|
||||
var/mob/living/living_pawn = controller.pawn
|
||||
for(var/mob/living/carbon/possible_cultist in oview(search_range, controller.pawn))
|
||||
if(IS_CULTIST(possible_cultist) && !(living_pawn.faction.Find(REF(possible_cultist))))
|
||||
if(IS_CULTIST(possible_cultist) && !(living_pawn.has_ally(possible_cultist)))
|
||||
return possible_cultist
|
||||
|
||||
return null
|
||||
|
||||
@@ -38,6 +38,7 @@ GLOBAL_DATUM(cargo_sloth, /mob/living/basic/sloth)
|
||||
ai_controller = /datum/ai_controller/basic_controller/sloth
|
||||
|
||||
/datum/emote/sloth
|
||||
abstract_type = /datum/emote/sloth
|
||||
mob_type_allowed_typecache = /mob/living/basic/sloth
|
||||
mob_type_blacklist_typecache = list()
|
||||
|
||||
|
||||
@@ -7,8 +7,8 @@
|
||||
name = "\improper Cybersun AI Core"
|
||||
desc = "An evil looking computer."
|
||||
icon = 'icons/mob/silicon/ai.dmi'
|
||||
icon_state = "ai-red"
|
||||
icon_living = "ai-red"
|
||||
icon_state = "ai-core"
|
||||
icon_living = "ai-core"
|
||||
gender = NEUTER
|
||||
status_flags = NONE
|
||||
basic_mob_flags = MOB_ROBOTIC
|
||||
@@ -45,9 +45,34 @@
|
||||
BARRAGE_ABILITY_TYPEPATH = BB_CYBERSUN_CORE_BARRAGE,
|
||||
)
|
||||
grant_actions_by_list(innate_actions)
|
||||
|
||||
update_appearance()
|
||||
|
||||
if(mapload && donk_ai_master)
|
||||
return INITIALIZE_HINT_LATELOAD
|
||||
|
||||
/mob/living/basic/cybersun_ai_core/update_overlays()
|
||||
. = ..()
|
||||
|
||||
// Lights
|
||||
var/lights_state = "lights_active"
|
||||
var/mutable_appearance/lights_overlay = mutable_appearance(icon, lights_state)
|
||||
lights_overlay.layer = FLOAT_LAYER
|
||||
lights_overlay.appearance_flags = RESET_COLOR | KEEP_APART
|
||||
. += lights_overlay
|
||||
. += emissive_appearance(icon, lights_state, src)
|
||||
|
||||
// Display
|
||||
var/screen_state = "ai-red"
|
||||
if(stat == DEAD)
|
||||
screen_state = "ai-red_dead"
|
||||
|
||||
var/mutable_appearance/screen_overlay = mutable_appearance(icon, screen_state)
|
||||
screen_overlay.layer = FLOAT_LAYER + 0.1
|
||||
screen_overlay.appearance_flags = RESET_COLOR | KEEP_APART
|
||||
. += screen_overlay
|
||||
. += emissive_appearance(icon, screen_state, src)
|
||||
|
||||
/mob/living/basic/cybersun_ai_core/LateInitialize()
|
||||
SSqueuelinks.add_to_queue(src, selfdestruct_queue_id)
|
||||
SSqueuelinks.pop_link(selfdestruct_queue_id)
|
||||
@@ -64,11 +89,13 @@
|
||||
|
||||
/obj/effect/temp_visual/cybersun_ai_core_death
|
||||
icon = 'icons/mob/silicon/ai.dmi'
|
||||
icon_state = "ai-red_dead"
|
||||
icon_state = "ai-core"
|
||||
duration = 2 SECONDS
|
||||
|
||||
/obj/effect/temp_visual/cybersun_ai_core_death/Initialize(mapload)
|
||||
. = ..()
|
||||
add_overlay("ai-red_dead")
|
||||
|
||||
playsound(src, 'sound/misc/metal_creak.ogg', vol = 100, vary = TRUE, pressure_affected = FALSE)
|
||||
Shake(1, 0, 2 SECONDS)
|
||||
addtimer(CALLBACK(src, PROC_REF(gib)), duration - 1, TIMER_DELETE_ME)
|
||||
|
||||
@@ -59,7 +59,7 @@
|
||||
if(!QDELETED(bodypart))
|
||||
qdel(bodypart)
|
||||
|
||||
/mob/living/basic/living_limb_flesh/Life(seconds_per_tick = SSMOBS_DT, times_fired)
|
||||
/mob/living/basic/living_limb_flesh/Life(seconds_per_tick = SSMOBS_DT)
|
||||
. = ..()
|
||||
if(stat == DEAD)
|
||||
return
|
||||
@@ -153,7 +153,7 @@
|
||||
|
||||
var/obj/item/bodypart/new_bodypart = new part_type()
|
||||
forceMove(new_bodypart)
|
||||
new_bodypart.replace_limb(target, TRUE)
|
||||
new_bodypart.replace_limb(target)
|
||||
register_to_limb(new_bodypart)
|
||||
|
||||
/mob/living/basic/living_limb_flesh/proc/owner_shocked(datum/source, shock_damage, shock_source, siemens_coeff, flags)
|
||||
|
||||
@@ -25,7 +25,7 @@
|
||||
icon_state = "floor"
|
||||
icon_living = "floor"
|
||||
mob_size = MOB_SIZE_HUGE
|
||||
mob_biotypes = MOB_SPECIAL
|
||||
mob_biotypes = MOB_SPECIAL|MOB_MINERAL
|
||||
status_flags = NONE
|
||||
death_message = ""
|
||||
unsuitable_atmos_damage = 0
|
||||
|
||||
@@ -17,7 +17,7 @@ GLOBAL_LIST_INIT(animatable_blacklist, typecacheof(list(
|
||||
maxHealth = 250
|
||||
health = 250
|
||||
gender = NEUTER
|
||||
mob_biotypes = NONE
|
||||
mob_biotypes = MOB_MINERAL
|
||||
pass_flags = PASSFLAPS
|
||||
melee_damage_lower = 8
|
||||
melee_damage_upper = 12
|
||||
@@ -283,7 +283,7 @@ GLOBAL_LIST_INIT(animatable_blacklist, typecacheof(list(
|
||||
copied_ref = null
|
||||
return ..()
|
||||
|
||||
/mob/living/basic/mimic/copy/Life(seconds_per_tick = SSMOBS_DT, times_fired)
|
||||
/mob/living/basic/mimic/copy/Life(seconds_per_tick = SSMOBS_DT)
|
||||
. = ..()
|
||||
if(!.) //dead or deleted
|
||||
return
|
||||
|
||||
@@ -50,7 +50,7 @@
|
||||
|
||||
/datum/ai_planning_subtree/random_speech/when_has_target/mimic_machine
|
||||
speech_chance = 7
|
||||
emote_hear = list()
|
||||
emote_hear = null
|
||||
speak = list(
|
||||
"HUMANS ARE IMPERFECT!",
|
||||
"YOU SHALL BE ASSIMILATED!",
|
||||
|
||||
@@ -3,7 +3,7 @@
|
||||
desc = "A real bonefied skeleton, doesn't seem like it wants to socialize."
|
||||
gender = NEUTER
|
||||
icon = 'icons/mob/simple/simple_human.dmi'
|
||||
mob_biotypes = MOB_UNDEAD|MOB_HUMANOID
|
||||
mob_biotypes = MOB_UNDEAD|MOB_HUMANOID|MOB_SKELETAL
|
||||
speak_emote = list("rattles")
|
||||
maxHealth = 40
|
||||
health = 40
|
||||
|
||||
@@ -112,7 +112,7 @@
|
||||
|
||||
var/list/created_slimes = list(src)
|
||||
var/list/slime_friends = list()
|
||||
for(var/faction_member in faction)
|
||||
for(var/faction_member in get_faction())
|
||||
var/mob/living/possible_friend = locate(faction_member) in GLOB.mob_living_list
|
||||
if(QDELETED(possible_friend))
|
||||
continue
|
||||
|
||||
@@ -29,12 +29,12 @@
|
||||
|
||||
// Check if the slime can drain the target
|
||||
/datum/ai_behavior/find_hunt_target/find_slime_food/valid_dinner(mob/living/basic/slime/hunter, mob/living/dinner, radius, datum/ai_controller/controller, seconds_per_tick)
|
||||
var/static/list/slime_faction
|
||||
if(isnull(slime_faction)) // This might look silly but by having this list pointer precached we can take advantage of the faster inline macro for this hot proc.
|
||||
slime_faction = string_list(list(FACTION_SLIME))
|
||||
|
||||
if(REF(dinner) in hunter.faction) //Don't eat our friends...
|
||||
return FALSE
|
||||
|
||||
var/static/list/slime_faction = list(FACTION_SLIME)
|
||||
if(faction_check(slime_faction, dinner.faction)) //Don't try to eat slimy things, no matter how hungry we are. Anyone else can be betrayed.
|
||||
// Macro here to squeeze as much speed as possible because this code gets exponentially HOT if people are doing a lot of xenobio.
|
||||
if(FAST_FACTION_CHECK(slime_faction, dinner.get_faction(), hunter.allies, dinner.allies, FALSE)) // Don't try to eat our friends, or slimy things, no matter how hungry we are. Anyone else can be betrayed.
|
||||
return FALSE
|
||||
|
||||
if(!hunter.can_feed_on(dinner, check_adjacent = FALSE)) //Are they tasty to slimes?
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
/datum/emote/slime
|
||||
abstract_type = /datum/emote/slime
|
||||
mob_type_allowed_typecache = /mob/living/basic/slime
|
||||
mob_type_blacklist_typecache = list()
|
||||
|
||||
|
||||
@@ -17,7 +17,7 @@
|
||||
balloon_alert(src, "not hungry!")
|
||||
return FALSE
|
||||
|
||||
if(check_friendship && (REF(meal) in faction))
|
||||
if(check_friendship && has_faction(REF(meal)))
|
||||
return FALSE
|
||||
|
||||
if(check_adjacent && (!Adjacent(meal) || !isturf(loc)))
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
|
||||
/mob/living/basic/slime/Life(seconds_per_tick = SSMOBS_DT, times_fired)
|
||||
/mob/living/basic/slime/Life(seconds_per_tick = SSMOBS_DT)
|
||||
. = ..()
|
||||
if(!.) //dead or deleted
|
||||
return
|
||||
@@ -9,7 +9,7 @@
|
||||
|
||||
handle_slime_stasis()
|
||||
|
||||
/mob/living/basic/slime/handle_environment(datum/gas_mixture/environment, seconds_per_tick, times_fired)
|
||||
/mob/living/basic/slime/handle_environment(datum/gas_mixture/environment, seconds_per_tick)
|
||||
..()
|
||||
if(bodytemperature <= (T0C - 40)) // stun temperature
|
||||
apply_status_effect(/datum/status_effect/freon, SLIME_COLD)
|
||||
|
||||
@@ -157,7 +157,7 @@
|
||||
/mob/living/basic/slime/random
|
||||
|
||||
/mob/living/basic/slime/random/Initialize(mapload, new_colour, new_life_stage)
|
||||
return ..(mapload, null, prob(50) ? SLIME_LIFE_STAGE_ADULT : SLIME_LIFE_STAGE_BABY)
|
||||
return ..(mapload, SLIME_TYPE_RANDOM, prob(50) ? SLIME_LIFE_STAGE_ADULT : SLIME_LIFE_STAGE_BABY)
|
||||
|
||||
///Friendly docile subtype
|
||||
/mob/living/basic/slime/pet
|
||||
@@ -197,10 +197,11 @@
|
||||
if(slime_type.transparent)
|
||||
alpha = SLIME_TRANSPARENCY_ALPHA
|
||||
|
||||
icon_living = "[slime_type.colour]-[life_stage]"
|
||||
icon_dead = !cores ? "[slime_type.colour]-cut" : "[slime_type.colour]-[life_stage]-dead"
|
||||
|
||||
if(stat != DEAD)
|
||||
icon_state = "[slime_type.colour]-[life_stage]"
|
||||
icon_state = icon_living
|
||||
if(current_mood && current_mood != SLIME_MOOD_NONE && !stat)
|
||||
add_overlay("aslime-[current_mood]")
|
||||
else
|
||||
@@ -273,8 +274,8 @@
|
||||
|
||||
/// Sets the slime's type, name and its icons.
|
||||
/// If not provided with a type it will instead be random
|
||||
/mob/living/basic/slime/proc/set_slime_type(new_type = null)
|
||||
if(isnull(new_type))
|
||||
/mob/living/basic/slime/proc/set_slime_type(new_type = SLIME_TYPE_RANDOM)
|
||||
if(new_type == SLIME_TYPE_RANDOM)
|
||||
new_type = pick(subtypesof(/datum/slime_type))
|
||||
|
||||
slime_type = possible_slime_types[new_type]
|
||||
|
||||
@@ -37,6 +37,7 @@
|
||||
ai_controller = /datum/ai_controller/basic_controller/ant
|
||||
|
||||
/datum/emote/ant
|
||||
abstract_type = /datum/emote/ant
|
||||
mob_type_allowed_typecache = /mob/living/basic/ant
|
||||
mob_type_blacklist_typecache = list()
|
||||
|
||||
|
||||
@@ -84,6 +84,7 @@
|
||||
))
|
||||
|
||||
/datum/emote/carp
|
||||
abstract_type = /datum/emote/carp
|
||||
mob_type_allowed_typecache = /mob/living/basic/carp
|
||||
mob_type_blacklist_typecache = list()
|
||||
|
||||
|
||||
@@ -33,7 +33,6 @@
|
||||
unsuitable_cold_damage = 4
|
||||
unsuitable_heat_damage = 4
|
||||
combat_mode = TRUE
|
||||
faction = list() // No allies but yourself
|
||||
pass_flags = PASSTABLE
|
||||
unique_name = TRUE
|
||||
lighting_cutoff_red = 22
|
||||
|
||||
@@ -119,4 +119,4 @@
|
||||
/mob/living/basic/eyeball/tamed(mob/living/tamer, atom/food)
|
||||
spin(spintime = 2 SECONDS, speed = 1)
|
||||
//become passive to the humens
|
||||
faction |= tamer.faction
|
||||
APPLY_FACTION_AND_ALLIES_FROM(src, tamer)
|
||||
|
||||
@@ -67,7 +67,7 @@
|
||||
/mob/living/basic/lightgeist/melee_attack(atom/target, list/modifiers, ignore_cooldown = FALSE)
|
||||
. = ..()
|
||||
if (. && isliving(target))
|
||||
faction |= REF(target) // Anyone we heal will treat us as a friend
|
||||
add_ally(target) // Anyone we heal will treat us as a friend
|
||||
|
||||
/mob/living/basic/lightgeist/ghost()
|
||||
. = ..()
|
||||
|
||||
@@ -21,7 +21,6 @@
|
||||
response_help_simple = "pet"
|
||||
response_disarm_continuous = "gently pushes"
|
||||
response_disarm_simple = "gently push"
|
||||
faction = list()
|
||||
ai_controller = /datum/ai_controller/basic_controller/meteor_heart
|
||||
habitable_atmos = null
|
||||
minimum_survivable_temperature = 0
|
||||
|
||||
@@ -60,7 +60,7 @@
|
||||
return
|
||||
make_migo_sound()
|
||||
|
||||
/mob/living/basic/migo/Life(seconds_per_tick = SSMOBS_DT, times_fired)
|
||||
/mob/living/basic/migo/Life(seconds_per_tick = SSMOBS_DT)
|
||||
. = ..()
|
||||
if(!.) //dead or deleted
|
||||
return
|
||||
|
||||
@@ -172,16 +172,16 @@
|
||||
return
|
||||
to_chat(affected_mob, span_notice("This food has a funny taste!"))
|
||||
|
||||
/datum/reagent/rat_spit/overdose_start(mob/living/affected_mob)
|
||||
/datum/reagent/rat_spit/overdose_start(mob/living/affected_mob, metabolization_ratio)
|
||||
. = ..()
|
||||
var/mob/living/carbon/victim = affected_mob
|
||||
if (istype(victim) && !(FACTION_RAT in victim.faction))
|
||||
if (istype(victim) && !victim.has_faction(FACTION_RAT))
|
||||
to_chat(victim, span_userdanger("With this last sip, you feel your body convulsing horribly from the contents you've ingested. As you contemplate your actions, you sense an awakened kinship with rat-kind and their newly risen leader!"))
|
||||
victim.faction |= FACTION_RAT
|
||||
victim.add_faction(FACTION_RAT)
|
||||
victim.vomit(VOMIT_CATEGORY_DEFAULT)
|
||||
metabolization_rate = 10 * REAGENTS_METABOLISM
|
||||
|
||||
/datum/reagent/rat_spit/on_mob_life(mob/living/carbon/affected_mob)
|
||||
/datum/reagent/rat_spit/on_mob_life(mob/living/carbon/affected_mob, metabolization_ratio)
|
||||
. = ..()
|
||||
if(prob(15))
|
||||
to_chat(affected_mob, span_notice("You feel queasy!"))
|
||||
|
||||
@@ -132,7 +132,7 @@
|
||||
return TRUE
|
||||
|
||||
/// Signal Handler Injection to handle Life() stuff for revenants
|
||||
/mob/living/basic/revenant/proc/on_life(seconds_per_tick = SSMOBS_DT, times_fired)
|
||||
/mob/living/basic/revenant/proc/on_life(seconds_per_tick = SSMOBS_DT)
|
||||
SIGNAL_HANDLER
|
||||
|
||||
if(dormant)
|
||||
@@ -283,7 +283,7 @@
|
||||
/mob/living/basic/revenant/med_hud_set_status()
|
||||
return //we use no hud
|
||||
|
||||
/mob/living/basic/revenant/dust(just_ash, drop_items, force)
|
||||
/mob/living/basic/revenant/dust(just_ash, drop_items, give_moodlet, force)
|
||||
death()
|
||||
|
||||
/mob/living/basic/revenant/gib()
|
||||
|
||||
@@ -119,9 +119,7 @@
|
||||
continue
|
||||
|
||||
light.visible_message(span_boldwarning("[light] suddenly flares brightly and begins to spark!"))
|
||||
var/datum/effect_system/spark_spread/light_sparks = new /datum/effect_system/spark_spread()
|
||||
light_sparks.set_up(4, 0, light)
|
||||
light_sparks.start()
|
||||
do_sparks(4, FALSE, light)
|
||||
new /obj/effect/temp_visual/revenant(get_turf(light))
|
||||
addtimer(CALLBACK(src, PROC_REF(overload_shock), light, caster), 2 SECONDS)
|
||||
|
||||
|
||||
@@ -37,6 +37,7 @@
|
||||
ai_controller = /datum/ai_controller/basic_controller/simple/simple_retaliate
|
||||
|
||||
/datum/emote/roro
|
||||
abstract_type = /datum/emote/roro
|
||||
mob_type_allowed_typecache = /mob/living/basic/roro
|
||||
mob_type_blacklist_typecache = list()
|
||||
|
||||
|
||||
@@ -46,7 +46,7 @@
|
||||
removed_from.remove_traits(applied_traits + TRAIT_WING_BUFFET_TIRED, REF(src))
|
||||
|
||||
/// Decay our accumulated additional tiredness
|
||||
/datum/action/cooldown/mob_cooldown/wing_buffet/proc/on_life(mob/living/liver, seconds_per_tick, times_fired)
|
||||
/datum/action/cooldown/mob_cooldown/wing_buffet/proc/on_life(mob/living/liver, seconds_per_tick)
|
||||
SIGNAL_HANDLER
|
||||
if (liver.stat == DEAD)
|
||||
return // not so life now buddy
|
||||
|
||||
@@ -140,7 +140,7 @@
|
||||
|
||||
/// Select scale colour with the colour picker
|
||||
/mob/living/basic/space_dragon/proc/select_colour()
|
||||
chosen_colour = tgui_color_picker(src, "What colour would you like to be?" , "Colour Selection", COLOR_WHITE) // BUBBERSTATION EDIT: TGUI COLOR PICKER
|
||||
chosen_colour = tgui_color_picker(src, "What colour would you like to be?" ,"Colour Selection", COLOR_WHITE)
|
||||
if(!chosen_colour) // Redo proc until we get a color
|
||||
to_chat(src, span_warning("Not a valid colour, please try again."))
|
||||
select_colour()
|
||||
|
||||
@@ -55,6 +55,7 @@
|
||||
var/apply_spider_antag = TRUE
|
||||
|
||||
/datum/emote/spider
|
||||
abstract_type = /datum/emote/spider
|
||||
mob_type_allowed_typecache = /mob/living/basic/spider
|
||||
mob_type_blacklist_typecache = list()
|
||||
|
||||
@@ -152,7 +153,7 @@
|
||||
|
||||
var/mob/living/basic/spider/giant/grown = change_mob_type(grow_as, get_turf(src), initial(grow_as.name))
|
||||
ADD_TRAIT(grown, TRAIT_WAS_EVOLVED, REF(src))
|
||||
grown.faction = faction.Copy()
|
||||
SET_FACTION_AND_ALLIES_FROM(grown, src)
|
||||
grown.directive = directive
|
||||
grown.set_name()
|
||||
grown.set_brute_loss(get_brute_loss())
|
||||
|
||||
@@ -55,7 +55,7 @@
|
||||
|
||||
/datum/action/cooldown/mob_cooldown/lay_eggs/proc/lay_egg()
|
||||
var/obj/effect/mob_spawn/ghost_role/spider/new_eggs = new egg_type(get_turf(owner))
|
||||
new_eggs.faction = owner.faction
|
||||
SET_FACTION_AND_ALLIES_FROM(new_eggs, owner)
|
||||
var/datum/action/cooldown/mob_cooldown/set_spider_directive/spider_directive = locate() in owner.actions
|
||||
if (spider_directive)
|
||||
new_eggs.directive = spider_directive.current_directive
|
||||
|
||||
@@ -9,7 +9,7 @@
|
||||
icon_dead = "human_male"
|
||||
gender = NEUTER
|
||||
combat_mode = TRUE
|
||||
mob_biotypes = MOB_HUMANOID
|
||||
mob_biotypes = MOB_HUMANOID|MOB_MINERAL
|
||||
gold_core_spawnable = NO_SPAWN
|
||||
|
||||
response_help_continuous = "touches"
|
||||
|
||||
@@ -10,7 +10,7 @@
|
||||
|
||||
gender = NEUTER
|
||||
status_flags = CANPUSH
|
||||
mob_biotypes = MOB_BUG|MOB_ROBOTIC
|
||||
mob_biotypes = MOB_BUG|MOB_ROBOTIC|MOB_MINERAL
|
||||
speak_emote = list("vibrates")
|
||||
|
||||
|
||||
|
||||
@@ -59,7 +59,7 @@
|
||||
AddElement(/datum/element/death_drops, /obj/item/stack/sheet/mineral/wood)
|
||||
AddComponent(/datum/component/aggro_emote, emote_list = string_list(list("growls")), emote_chance = 20)
|
||||
|
||||
/mob/living/basic/tree/Life(seconds_per_tick = SSMOBS_DT, times_fired)
|
||||
/mob/living/basic/tree/Life(seconds_per_tick = SSMOBS_DT)
|
||||
. = ..()
|
||||
if(!.) //dead or deleted
|
||||
return
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user