Merge branch 'master' of https://github.com/tgstation/tgstation into upstream-15-10-2025

This commit is contained in:
Roxy
2025-10-15 19:34:41 -04:00
656 changed files with 24772 additions and 15866 deletions
+1 -1
View File
@@ -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) && owner.CanReach(victim))
if(faction_check(victim.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!"))
@@ -372,7 +372,7 @@
update_bot_mode(new_mode = BOT_IDLE)
return
if(CanReach(patient))
if(patient.IsReachableBy(src))
melee_attack(patient)
/datum/id_trim/medibot
+3 -3
View File
@@ -597,7 +597,7 @@
. = ..()
var/list/reachable_turfs = list()
for(var/turf/adjacent_turf in RANGE_TURFS(1, owner.loc))
if(adjacent_turf == owner.loc || !owner.CanReach(adjacent_turf) || !isopenturf(adjacent_turf))
if(adjacent_turf == owner.loc || !adjacent_turf.IsReachableBy(owner) || !isopenturf(adjacent_turf))
continue
reachable_turfs += adjacent_turf
@@ -625,10 +625,10 @@
/datum/action/cooldown/exquisite_bunch/Trigger(mob/clicker, trigger_flags, atom/target)
if(activating)
return
var/bunch_turf = get_step(owner.loc, owner.dir)
var/atom/bunch_turf = get_step(owner.loc, owner.dir)
if(!bunch_turf)
return
if(!owner.CanReach(bunch_turf) || !isopenturf(bunch_turf))
if(!bunch_turf.IsReachableBy(owner) || !isopenturf(bunch_turf))
owner.balloon_alert(owner, "can't do that here!")
return
activating = TRUE
@@ -36,20 +36,19 @@
smashes_walls = FALSE
melee_attack_cooldown = 2 SECONDS
/mob/living/basic/construct/juggernaut/bullet_act(obj/projectile/bullet)
if(!istype(bullet, /obj/projectile/energy) && !istype(bullet, /obj/projectile/beam))
/mob/living/basic/construct/juggernaut/projectile_hit(obj/projectile/hitting_projectile, def_zone, piercing_hit, blocked)
if(!istype(hitting_projectile, /obj/projectile/energy) && !istype(hitting_projectile, /obj/projectile/beam))
return ..()
if(!prob(40 - round(bullet.damage / 3))) // reflect chance
if(!prob(40 - round(hitting_projectile.damage / 3))) // reflect chance
return ..()
apply_damage(bullet.damage * 0.5, bullet.damage_type)
apply_damage(hitting_projectile.damage * 0.5, hitting_projectile.damage_type)
visible_message(
span_danger("\The [bullet] is reflected by [src]'s armored shell!"),
span_userdanger("\The [bullet] is reflected by your armored shell!"),
span_danger("\The [hitting_projectile] is reflected by [src]'s armored shell!"),
span_userdanger("\The [hitting_projectile] is reflected by your armored shell!"),
)
bullet.reflect(src)
hitting_projectile.reflect(src)
return BULLET_ACT_FORCE_PIERCE // complete projectile permutation
// Alternate juggernaut themes
@@ -295,3 +295,6 @@
if(built_in_camera?.can_use())
return TRUE
return ..()
/mob/living/basic/drone/hypnosis_vulnerable()
return FALSE //It obeys its laws
@@ -18,6 +18,9 @@
var/static/list/actions_to_add = list(
/datum/action/cooldown/spell/fire_sworn,
/datum/action/cooldown/spell/jaunt/ethereal_jaunt/ash,
/datum/action/cooldown/spell/pointed/cleave,
)
grant_actions_by_list(actions_to_add)
/mob/living/basic/heretic_summon/ash_spirit/Life(seconds_per_tick, times_fired)
. = ..()
adjustBruteLoss(-3) // 3 health passively healing
@@ -33,6 +33,7 @@
)
AddElement(/datum/element/death_drops, loot)
GRANT_ACTION(/datum/action/cooldown/spell/jaunt/mirror_walk)
ADD_TRAIT(src, TRAIT_UNHITTABLE_BY_LASERS, INNATE_TRAIT)
/mob/living/basic/heretic_summon/maid_in_the_mirror/death(gibbed)
var/turf/death_turf = get_turf(src)
@@ -50,14 +51,14 @@
return
// If we have health, we take some damage
if(health > (maxHealth * 0.125))
if(health > (maxHealth * 0.02))
visible_message(
span_warning("[src] seems to fade in and out slightly."),
span_userdanger("[user]'s gaze pierces your every being!"),
)
recent_examiner_refs += user_ref
apply_damage(maxHealth * 0.1) // We take 10% of our health as damage upon being examined
apply_damage(maxHealth * 0.02) // We take 2% of our health as damage upon being examined
playsound(src, 'sound/effects/ghost2.ogg', 40, TRUE)
addtimer(CALLBACK(src, PROC_REF(clear_recent_examiner), user_ref), recent_examine_damage_cooldown, TIMER_DELETE_ME)
animate(src, alpha = 120, time = 0.5 SECONDS, easing = ELASTIC_EASING, loop = 2, flags = ANIMATION_PARALLEL)
@@ -78,3 +79,10 @@
recent_examiner_refs -= mob_ref
heal_overall_damage(5)
/mob/living/basic/heretic_summon/maid_in_the_mirror/melee_attack(atom/target, list/modifiers, ignore_cooldown)
. = ..()
if(!. || !isliving(target))
return
var/mob/living/living_target = target
living_target.apply_status_effect(/datum/status_effect/void_chill, 1)
@@ -35,29 +35,94 @@
mob_size = MOB_SIZE_HUGE
layer = LARGE_MOB_LAYER
flags_1 = PREVENT_CONTENTS_EXPLOSION_1
lighting_cutoff_red = 12
lighting_cutoff_green = 15
lighting_cutoff_blue = 34
sight = SEE_TURFS|SEE_MOBS|SEE_OBJS
ai_controller = /datum/ai_controller/basic_controller/star_gazer
/// Reference to the mob which summoned us
var/datum/weakref/summoner
/// How far we can go before being pulled back
var/leash_range = 20
/// Timer for finding a ghost so it doesn't spam dead chat with requests
var/begging_timer
///---- Abilities given to the star gazer mob
var/list/abilities_to_grant = list(
/datum/action/cooldown/spell/conjure/cosmic_expansion,
/datum/action/cooldown/spell/pointed/projectile/star_blast,
/datum/action/cooldown/recall_stargazer,
/datum/action/cooldown/spell/stargazer_laser,
)
/mob/living/basic/heretic_summon/star_gazer/Initialize(mapload)
/mob/living/basic/heretic_summon/star_gazer/Initialize(mapload, mob/living/master)
. = ..()
for(var/datum/action/cooldown/spell/spell as anything in abilities_to_grant)
spell = new spell(src)
spell.Grant(src)
var/datum/action/cooldown/spell/stargazer_laser/laser = locate() in actions
if(master)
summoner = WEAKREF(master)
if(laser)
laser.our_master = WEAKREF(master)
AddComponent(/datum/component/seethrough_mob)
var/static/list/death_loot = list(/obj/effect/temp_visual/cosmic_domain)
AddElement(/datum/element/death_drops, death_loot)
AddElement(/datum/element/death_drops, /obj/effect/temp_visual/cosmic_domain)
AddElement(/datum/element/death_explosion, 3, 6, 12)
AddElement(/datum/element/footstep, FOOTSTEP_MOB_SHOE)
AddElement(/datum/element/wall_smasher, ENVIRONMENT_SMASH_RWALLS)
AddElement(/datum/element/simple_flying)
AddElement(/datum/element/effect_trail, /obj/effect/forcefield/cosmic_field/fast)
AddElement(/datum/element/effect_trail/cosmic_field/antiprojectile, /obj/effect/forcefield/cosmic_field/fast)
AddElement(/datum/element/ai_target_damagesource)
AddComponent(/datum/component/regenerator, outline_colour = "#b97a5d")
ADD_TRAIT(src, TRAIT_SPACEWALK, INNATE_TRAIT)
ADD_TRAIT(src, TRAIT_LAVA_IMMUNE, INNATE_TRAIT)
ADD_TRAIT(src, TRAIT_ASHSTORM_IMMUNE, INNATE_TRAIT)
ADD_TRAIT(src, TRAIT_NO_TELEPORT, MEGAFAUNA_TRAIT)
ADD_TRAIT(src, TRAIT_MARTIAL_ARTS_IMMUNE, MEGAFAUNA_TRAIT)
ADD_TRAIT(src, TRAIT_NO_FLOATING_ANIM, INNATE_TRAIT)
ADD_TRAIT(src, TRAIT_MAGICALLY_GIFTED, INNATE_TRAIT)
set_light(4, l_color = "#dcaa5b")
INVOKE_ASYNC(src, PROC_REF(beg_for_ghost))
RegisterSignal(src, COMSIG_MOB_GHOSTIZED, PROC_REF(beg_for_ghost))
/mob/living/basic/heretic_summon/star_gazer/Destroy()
deltimer(begging_timer)
return ..()
/// Tries to find a ghost to take control of the mob. If no ghost accepts, ask again in a bit
/mob/living/basic/heretic_summon/star_gazer/proc/beg_for_ghost()
if(timeleft(begging_timer) && !client)
return
begging_timer = addtimer(CALLBACK(src, PROC_REF(beg_for_ghost)), 2 MINUTES, TIMER_STOPPABLE | TIMER_UNIQUE) // Keep begging until someone accepts
var/mob/chosen_ghost = SSpolling.poll_ghost_candidates(
"Do you want to play as an ascended heretic's stargazer?",
check_jobban = ROLE_HERETIC,
poll_time = 20 SECONDS,
ignore_category = POLL_IGNORE_HERETIC_MONSTER,
alert_pic = mutable_appearance('icons/effects/eldritch.dmi', "cosmic_diamond"),
jump_target = src,
role_name_text = "star gazer",
amount_to_pick = 1
)
if(chosen_ghost)
PossessByPlayer(chosen_ghost.key)
deltimer(begging_timer)
/// Connects these two mobs by a leash
/mob/living/basic/heretic_summon/star_gazer/proc/leash_to(atom/movable/leashed, atom/movable/leashed_to)
leashed.AddComponent(\
/datum/component/leash,\
owner = leashed_to,\
distance = leash_range,\
force_teleport_out_effect = /obj/effect/temp_visual/guardian/phase/out,\
force_teleport_in_effect = /obj/effect/temp_visual/guardian/phase,\
)
// Star gazer attacks everything around itself applies a spooky mark
/mob/living/basic/heretic_summon/star_gazer/melee_attack(mob/living/target, list/modifiers, ignore_cooldown)
if(target == summoner?.resolve())
return FALSE
. = ..()
if (!. || !isliving(target))
return
@@ -74,6 +139,261 @@
do_attack_animation(nearby_mob, ATTACK_EFFECT_SLASH)
log_combat(src, nearby_mob, "slashed")
/datum/action/cooldown/recall_stargazer
name = "Seek master"
desc = "Teleports you to your master"
background_icon_state = "bg_heretic"
overlay_icon_state = "bg_heretic_border"
button_icon = 'icons/mob/actions/actions_ecult.dmi'
button_icon_state = "stargazer_menu"
check_flags = NONE
cooldown_time = 5 SECONDS
/datum/action/cooldown/recall_stargazer/Activate(atom/target)
var/mob/living/basic/heretic_summon/star_gazer/real_owner = owner
var/mob/living/master = real_owner.summoner?.resolve()
if(!master)
return FALSE
do_teleport(owner, master, no_effects = TRUE, channel = TELEPORT_CHANNEL_MAGIC, forced = TRUE)
StartCooldown()
return TRUE
/datum/action/cooldown/spell/stargazer_laser
name = "Star Gaze"
desc = "Generates a massive death beam that eradicates everything in it's path. \
Has it's own gravitational pull, sucking in new victims."
background_icon_state = "bg_heretic"
overlay_icon_state = "bg_heretic_border"
button_icon = 'icons/mob/actions/actions_ecult.dmi'
button_icon_state = "gazer_beam_charge"
check_flags = NONE
cooldown_time = 30 SECONDS
invocation = "SH''P D' W''P"
invocation_type = INVOCATION_SHOUT
spell_requirements = NONE
/// list of turfs we are hitting while shooting our beam
var/list/turf/targets
/// The laser beam we generate
var/datum/beam/giga_laser
/// Timer that handles the damage ticking
var/damage_timer
/// Reference to our summoner so that we don't disintegrate them by accident
var/datum/weakref/our_master
/// The overlay on the caster when they fire the beam
var/obj/effect/abstract/gazer_orb/orb_visual
/// The visual effect at the beginning of the laser
var/obj/effect/abstract/gazer_beam/beam_visual
/// List of visual effects for the beam, in between and in the end
var/list/beam_fillings
/// Sound loop for the active laser
var/datum/looping_sound/gazer_beam/sound_loop
/// The visual effect at the end of the laser
var/obj/effect/abstract/gazer_beamend/end_visual
/// Tracks how many times the beam has processed, after the maximum amount of cycles it will forcibly end the beam
var/cycle_tracker = 0
/datum/action/cooldown/spell/stargazer_laser/cast(atom/target)
. = ..()
cooldown_time = initial(cooldown_time)
if(damage_timer)
stop_beaming()
var/turf/check_turf = get_step(owner, owner.dir)
var/list/turf/targets_left = list()
targets_left += get_step(check_turf, turn(owner.dir, 90))
var/list/turf/targets_right = list()
targets_right += get_step(check_turf, turn(owner.dir, -90))
LAZYINITLIST(targets)
while(check_turf && length(targets) < 20)
targets += check_turf
check_turf = get_step(check_turf, owner.dir)
targets_left += get_step(check_turf, turn(owner.dir, 90))
targets_right += get_step(check_turf, turn(owner.dir, -90))
if(!LAZYLEN(targets))
return
RegisterSignals(owner, list(COMSIG_MOVABLE_MOVED, COMSIG_ATOM_DIR_CHANGE), PROC_REF(stop_beaming))
beam_fillings = list()
cycle_tracker = 0
orb_visual = new(get_step(owner, owner.dir))
var/beam_timer = addtimer(CALLBACK(src, PROC_REF(open_laser), owner, targets), 2.2 SECONDS, TIMER_STOPPABLE)
playsound(owner, 'sound/mobs/non-humanoids/stargazer/beam_open.ogg', 50, FALSE)
if(!do_after(owner, 3 SECONDS, owner))
cooldown_time = 1 SECONDS
deltimer(beam_timer)
QDEL_NULL(orb_visual)
QDEL_NULL(beam_visual)
QDEL_NULL(end_visual)
for(var/atom/to_delete as anything in beam_fillings)
QDEL_NULL(to_delete)
targets = null
return
sound_loop.start(owner)
QDEL_NULL(orb_visual)
beam_visual.icon_state = "gazer_beam_active"
beam_visual.update_appearance(UPDATE_ICON)
end_visual.icon_state = "gazer_beam_end"
end_visual.update_appearance(UPDATE_ICON)
targets += targets_left
targets += targets_right
process_beam()
/datum/action/cooldown/spell/stargazer_laser/Destroy()
QDEL_NULL(sound_loop)
return ..()
/datum/action/cooldown/spell/stargazer_laser/New(Target, original)
. = ..()
sound_loop = new
/// Spawns the beginning of the laser, uses `targets` to determine the rotation
/datum/action/cooldown/spell/stargazer_laser/proc/open_laser(mob/owner, list/turf/targets)
beam_visual = new(get_step(get_step(owner, owner.dir), owner.dir), targets[length(targets)])
end_visual = new(targets[length(targets)], owner)
for(var/turf/to_fill as anything in (get_line(targets[4], targets[length(targets)-2])))
var/obj/effect/abstract/gazer_beam_filling/new_filling = new(to_fill, owner.dir)
beam_fillings += new_filling
// Visual effect of the big orb when you start channeling the laser
/obj/effect/abstract/gazer_orb
icon = 'icons/effects/160x160.dmi'
icon_state = "gazer_beam_charge"
SET_BASE_VISUAL_PIXEL(-64, -64)
// Visual effect at the start of the beam, has an opening/active/closing state
/obj/effect/abstract/gazer_beam
icon = 'icons/effects/beam96x96.dmi'
SET_BASE_VISUAL_PIXEL(-32, -32)
/obj/effect/abstract/gazer_beam/Initialize(mapload, turf/target)
. = ..()
if(!target)
return INITIALIZE_HINT_QDEL
var/Angle = get_angle_raw(x, y, pixel_x, pixel_y, target.x , target.y, target.pixel_x, target.pixel_y)
var/matrix/transform_matrix = matrix()
Angle = round(Angle, 45)
transform_matrix.Turn(Angle-90)
transform_matrix.Scale(2, 2)
transform = transform_matrix
flick("gazer_beam_start", src)
// Visual effect of the middle of the beam, has an opening/active/closing state
/obj/effect/abstract/gazer_beam_filling
icon = 'icons/effects/beam.dmi'
icon_state = "gazer_beam"
/obj/effect/abstract/gazer_beam_filling/Initialize(mapload, direction)
. = ..()
if(!direction)
return INITIALIZE_HINT_QDEL
var/Angle = dir2angle(direction)
var/matrix/transform_matrix = matrix()
transform_matrix.Turn(Angle)
transform_matrix.Scale(2, 2)
transform = transform_matrix
flick("gazer_beam_end_opening", src)
/obj/effect/abstract/gazer_beam_filling/proc/pull_victims()
for(var/atom/movable/movable_atom in orange(5, src))
if((movable_atom.anchored || movable_atom.move_resist >= MOVE_FORCE_EXTREMELY_STRONG))
continue
if(ismob(movable_atom))
var/mob/pulled_mob = movable_atom
if(pulled_mob.mob_negates_gravity())
continue
step_towards(movable_atom, src)
// Visual effect at the end of the beam, has an opening/active/closing state
/obj/effect/abstract/gazer_beamend
icon = 'icons/effects/beam.dmi'
/obj/effect/abstract/gazer_beamend/Initialize(mapload, atom/origin)
. = ..()
if(!origin)
return INITIALIZE_HINT_QDEL
var/Angle = get_angle_raw(origin.x , origin.y, origin.pixel_x, origin.pixel_y, x, y, pixel_x, pixel_y)
var/matrix/transform_matrix = matrix()
Angle = round(Angle, 45)
transform_matrix.Turn(Angle)
transform_matrix.Scale(2, 2)
transform = transform_matrix
flick("gazer_beam_end_opening", src)
/datum/looping_sound/gazer_beam
mid_sounds = list('sound/mobs/non-humanoids/stargazer/beam_loop_one.ogg')
mid_length = 109
volume = 80
/obj/effect/ebeam/phase_in // Beam subtype that has a "windup" phase
alpha = 0
/obj/effect/ebeam/phase_in/Initialize(mapload)
. = ..()
animate(src, 2 SECONDS, alpha = 255, transform = matrix(3, 1, MATRIX_SCALE))
/obj/effect/ebeam/phased_in/Initialize(mapload, beam_owner) // phased in, fully powered laser
. = ..()
transform = matrix(2, 2, MATRIX_SCALE)
/// Recursive proc which affects whatever is caught within the beam
/datum/action/cooldown/spell/stargazer_laser/proc/process_beam()
if(cycle_tracker > 33)
stop_beaming()
for(var/obj/effect/abstract/gazer_beam_filling/fillings as anything in beam_fillings)
if(prob(98))
continue
// 2% chance to pull you towards the beam
fillings.pull_victims()
for(var/turf/target as anything in targets)
if(iswallturf(target))
var/turf/closed/wall/wall_target = target
wall_target.dismantle_wall(devastated = TRUE)
continue
if(isfloorturf(target))
var/turf/open/floor/to_burn = target
to_burn.burn_tile()
for(var/victim in target)
if(isobj(victim))
var/obj/to_obliterate = victim
if(to_obliterate.resistance_flags & INDESTRUCTIBLE)
continue
to_obliterate.atom_destruction(FIRE)
if(isliving(victim))
if(victim == our_master?.resolve())
continue
var/mob/living/living_victim = victim
if(living_victim.stat > CONSCIOUS)
playsound(living_victim, 'sound/effects/supermatter.ogg', 80, TRUE)
living_victim.visible_message(
span_danger("You see [living_victim] engulfed in the scorching wrath of the cosmos. \
For a moment, you see their silhouette flail in agony before fading to mere atoms."),
span_boldbig(span_hypnophrase("THE POWER OF THE COSMOS ITSELF POURS OUT OVER YOUR FORM. \
WAVES OF HEAT LATCH ONTO YOUR BODY, PULLING IT APART AT THE SEAMS. \
YOUR TOTAL ANNIHILATION TAKES ONLY A MOMENT BEFORE YOU ARE REDUCED BACK TO WHAT YOU ALWAYS WERE. \
MOTES OF MERE DUST..."))
)
living_victim.dust()
living_victim.emote("scream")
living_victim.apply_status_effect(/datum/status_effect/star_mark)
living_victim.apply_damage(damage = 30, damagetype = BURN, spread_damage = TRUE)
cycle_tracker++
damage_timer = addtimer(CALLBACK(src, PROC_REF(process_beam)), 0.3 SECONDS, TIMER_STOPPABLE)
/// Stops the beam after we cancel it
/datum/action/cooldown/spell/stargazer_laser/proc/stop_beaming()
SIGNAL_HANDLER
sound_loop.stop()
UnregisterSignal(owner, list(COMSIG_MOVABLE_MOVED, COMSIG_ATOM_DIR_CHANGE))
QDEL_NULL(giga_laser)
QDEL_NULL(beam_visual)
QDEL_NULL(end_visual)
QDEL_LIST(beam_fillings)
deltimer(damage_timer)
damage_timer = null
targets = null
/datum/ai_controller/basic_controller/star_gazer
blackboard = list(
BB_TARGETING_STRATEGY = /datum/targeting_strategy/basic,
@@ -83,7 +83,7 @@
if(stat != CONSCIOUS)
return COMPONENT_BULLET_PIERCED
///high penetration bullets should still go through. No goldgrub can save you from the colossus' death bolts.
/// High penetration bullets should still go through. No goldgrub can save you from the colossus' death bolts.
if(prob(hitting_projectile.armour_penetration))
return NONE
@@ -94,6 +94,7 @@
playsound(src, 'sound/effects/splat.ogg', 50, TRUE)
for(var/obj/item/stack/ore/ore in src)
ore.forceMove(loc)
if(!gibbed)
visible_message(span_danger("[src] spits out its consumed ores!"))
@@ -112,7 +112,7 @@
/datum/ai_behavior/goliath_dig/perform(seconds_per_tick, datum/ai_controller/controller, target_key)
var/turf/target_turf = controller.blackboard[target_key]
var/mob/living/basic/basic_mob = controller.pawn
if(!basic_mob.CanReach(target_turf))
if(!target_turf.IsReachableBy(basic_mob))
return AI_BEHAVIOR_DELAY
basic_mob.melee_attack(target_turf)
return AI_BEHAVIOR_DELAY | AI_BEHAVIOR_SUCCEEDED
@@ -37,7 +37,7 @@
var/times_to_attack = 4
/datum/action/cooldown/mob_cooldown/mook_ability/mook_leap/Activate(atom/target)
if(owner.CanReach(target))
if(target.IsReachableBy(owner))
attack_combo(target)
StartCooldown()
return TRUE
@@ -74,14 +74,14 @@
owner.throw_at(target = final_turf, range = 7, speed = 1, spin = FALSE, callback = CALLBACK(src, PROC_REF(attack_combo), target))
/datum/action/cooldown/mob_cooldown/mook_ability/mook_leap/proc/attack_combo(atom/target)
if(!owner.CanReach(target))
if(!target.IsReachableBy(owner))
return FALSE
for(var/i in 0 to (times_to_attack - 1))
addtimer(CALLBACK(src, PROC_REF(attack_target), target), i * attack_interval)
/datum/action/cooldown/mob_cooldown/mook_ability/mook_leap/proc/attack_target(atom/target)
if(!owner.CanReach(target) || owner.stat == DEAD)
if(!target.IsReachableBy(owner) || owner.stat == DEAD)
return
var/mob/living/basic/basic_owner = owner
basic_owner.melee_attack(target, ignore_cooldown = TRUE)
@@ -299,8 +299,7 @@ GLOBAL_LIST_EMPTY(raptor_population)
icon_dead = "raptor_black_dead"
maxHealth = 400
health = 400
speed = 1
ridable_component = /datum/component/riding/creature/raptor/fast
speed = 1.5
melee_damage_lower = 20
melee_damage_upper = 25
raptor_color = RAPTOR_BLACK
@@ -312,8 +311,7 @@ GLOBAL_LIST_EMPTY(raptor_population)
icon_state = "raptor_yellow"
icon_living = "raptor_yellow"
icon_dead = "raptor_yellow_dead"
ridable_component = /datum/component/riding/creature/raptor/fast
speed = 1
speed = 1.5
raptor_color = RAPTOR_YELLOW
dex_description = "This breed possesses greasy fast speed, DEMON speed, making light work of long pilgrimages. It's said that a thunderclap could be heard when this breed reaches its maximum speed."
child_path = /mob/living/basic/raptor/baby_raptor/yellow
@@ -21,7 +21,7 @@
var/list/data = list()
var/mob/living/basic/raptor/my_raptor = raptor.resolve()
data["raptor_image"] = icon2base64(getFlatIcon(image(icon = my_raptor.icon, icon_state = my_raptor.icon_state)))
data["raptor_image"] = icon2base64(icon(icon = my_raptor.icon, icon_state = my_raptor.icon_state, frame = 1))
data["raptor_attack"] = my_raptor.melee_damage_lower
data["raptor_health"] = my_raptor.maxHealth
data["raptor_speed"] = my_raptor.speed
@@ -33,7 +33,7 @@
var/obj/effect/overlay/happiness_overlay/display = new
display.set_hearts(happiness_percentage)
display.pixel_y = ICON_SIZE_Y * 0.5
data["raptor_happiness"] = icon2base64(getFlatIcon(display))
data["raptor_happiness"] = icon2base64(getFlatIcon(display, no_anim = TRUE))
qdel(display)
var/datum/raptor_inheritance/inherit = my_raptor.inherited_stats
@@ -165,7 +165,7 @@
/mob/living/basic/mining_drone/ui_static_data(mob/user)
var/list/data = list()
data["bot_icon"] = icon2base64(getFlatIcon(src))
data["bot_icon"] = icon2base64(getFlatIcon(src, no_anim = TRUE))
data["possible_colors"] = list()
for(var/color in possible_colors)
data["possible_colors"] += list(list(
@@ -292,7 +292,7 @@
possible_headwear += item
if(!length(possible_headwear))
for(var/obj/item/item in orange(1))
if(ispath(item.dog_fashion, /datum/dog_fashion/head) && CanReach(item))
if(ispath(item.dog_fashion, /datum/dog_fashion/head) && item.IsReachableBy(src))
possible_headwear += item
if(!length(possible_headwear))
return
@@ -81,7 +81,7 @@ GLOBAL_LIST_INIT(pet_options, list(
for(var/color in possible_colors)
demo_carrier.set_greyscale(possible_colors[color])
list_to_return[color] = icon2base64(getFlatIcon(demo_carrier))
list_to_return[color] = icon2base64(getFlatIcon(demo_carrier, no_anim = TRUE))
qdel(demo_carrier)
return list_to_return
@@ -85,7 +85,7 @@
for(var/atom/movable/movable in orange(victim, 1))
if(movable == victim)
continue
if(!victim.CanReach(movable) || movable.invisibility > victim.see_invisible)
if(!movable.IsReachableBy(victim) || movable.invisibility > victim.see_invisible)
continue
candidates += movable
if(!length(candidates))
@@ -65,7 +65,7 @@
/mob/living/basic/ghost/proc/give_identity()
if(random_identity)
ghost_hairstyle = random_hairstyle() //This only gives us the hairstyle name, not the icon_state (which we need).
ghost_hair_color = "#[random_color()]"
ghost_hair_color = random_hair_color()
if(prob(50)) //Only a chance at also getting facial hair
ghost_facial_hairstyle = random_facial_hairstyle()
@@ -299,7 +299,7 @@
/mob/living/basic/revenant/narsie_act()
return //most humans will now be either bones or harvesters, but we're still un-alive.
/mob/living/basic/revenant/bullet_act()
/mob/living/basic/revenant/projectile_hit(obj/projectile/hitting_projectile, def_zone, piercing_hit, blocked)
if(!HAS_TRAIT(src, TRAIT_REVENANT_REVEALED) || dormant)
return BULLET_ACT_FORCE_PIERCE
return ..()
@@ -37,9 +37,9 @@
r_hand = /obj/item/knife/combat/survival
var/projectile_deflect_chance = 0
/mob/living/basic/trooper/syndicate/melee/bullet_act(obj/projectile/projectile)
/mob/living/basic/trooper/syndicate/melee/projectile_hit(obj/projectile/hitting_projectile, def_zone, piercing_hit, blocked)
if(prob(projectile_deflect_chance))
visible_message(span_danger("[src] blocks [projectile] with its shield!"))
visible_message(span_danger("[src] blocks [hitting_projectile] with its shield!"))
return BULLET_ACT_BLOCK
return ..()