mirror of
https://github.com/Bubberstation/Bubberstation.git
synced 2026-08-25 14:08:31 +01:00
[MIRROR] convert the eyeball a basic monster [MDB IGNORE] (#23043)
* convert the eyeball a basic monster (#77411) ## About The Pull Request I have created a basic eyeball monster with new abilities and behaviors. The eyeball has a unique power that allows it to glare at humans and make them slow for a short period. However, this ability only works if the human can see the eyeball monster. If a person is blind or unable to see the eyeball, the ability won't affect them. Also, if someone turns their back to the eyeball, it cannot use the ability on them. But be cautious because the eyeball will try to position itself in front of the person's face to use its power. The eyeball is hostile towards all humans except for the blind ones and those with significant eye damage. It has a compassionate side too, as it loves to help people with eye damage by providing small healing to their eyes. Furthermore, the eyeball has a fondness for eating carrots, which not only satisfies its appetite but also grants it a small health boost. To add to its appearance, I've given it a new, larger, and scarier sprite. However, I am open to changing it back to the old sprite if the player prefers it that way. Additionally, the eyeball displays emotions, and if you hit it, it will cry tears as a sign of pain or sadness.  ## Why It's Good For The Game the eyeball now have more depth and character to his behavier. ## Changelog 🆑 refactor: the eyeball is a basic monster, please report any bugs sprites: the eyeball now is bigger and scarier and now he will cry when u hit him /🆑 * convert the eyeball a basic monster --------- Co-authored-by: Ben10Omintrix <138636438+Ben10Omintrix@users.noreply.github.com>
This commit is contained in:
co-authored by
Ben10Omintrix
parent
d4612dec4e
commit
d4074241c1
@@ -0,0 +1,123 @@
|
||||
/mob/living/basic/eyeball
|
||||
name = "eyeball"
|
||||
desc = "An odd looking creature, it won't stop staring..."
|
||||
icon = 'icons/mob/simple/carp.dmi'
|
||||
icon_state = "eyeball"
|
||||
icon_living = "eyeball"
|
||||
icon_gib = ""
|
||||
gender = NEUTER
|
||||
gold_core_spawnable = HOSTILE_SPAWN
|
||||
basic_mob_flags = DEL_ON_DEATH
|
||||
gender = NEUTER
|
||||
mob_biotypes = MOB_ORGANIC
|
||||
|
||||
response_help_continuous = "pets"
|
||||
response_help_simple = "pet"
|
||||
response_disarm_continuous = "gently pushes aside"
|
||||
response_disarm_simple = "gently push aside"
|
||||
|
||||
maxHealth = 30
|
||||
health = 30
|
||||
obj_damage = 10
|
||||
melee_damage_lower = 8
|
||||
melee_damage_upper = 12
|
||||
|
||||
attack_verb_continuous = "bites"
|
||||
attack_verb_simple = "bite"
|
||||
attack_sound = 'sound/weapons/bite.ogg'
|
||||
attack_vis_effect = ATTACK_EFFECT_BITE
|
||||
|
||||
faction = list(FACTION_SPOOKY)
|
||||
speak_emote = list("telepathically cries")
|
||||
|
||||
habitable_atmos = list("min_oxy" = 0, "max_oxy" = 0, "min_plas" = 0, "max_plas" = 0, "min_co2" = 0, "max_co2" = 0, "min_n2" = 0, "max_n2" = 0)
|
||||
minimum_survivable_temperature = T0C
|
||||
maximum_survivable_temperature = T0C + 1500
|
||||
sight = SEE_SELF|SEE_MOBS|SEE_OBJS|SEE_TURFS
|
||||
|
||||
lighting_cutoff_red = 40
|
||||
lighting_cutoff_green = 20
|
||||
lighting_cutoff_blue = 30
|
||||
|
||||
ai_controller = /datum/ai_controller/basic_controller/eyeball
|
||||
///how much we will heal eyes
|
||||
var/healing_factor = 3
|
||||
/// is this eyeball crying?
|
||||
var/crying = FALSE
|
||||
/// the crying overlay we add when is hit
|
||||
var/mutable_appearance/on_hit_overlay
|
||||
|
||||
///cooldown to heal eyes
|
||||
COOLDOWN_DECLARE(eye_healing)
|
||||
|
||||
/mob/living/basic/eyeball/Initialize(mapload)
|
||||
. = ..()
|
||||
var/datum/action/cooldown/spell/pointed/death_glare/glare = new(src)
|
||||
glare.Grant(src)
|
||||
ai_controller.set_blackboard_key(BB_GLARE_ABILITY, glare)
|
||||
AddElement(/datum/element/simple_flying)
|
||||
AddComponent(/datum/component/tameable, food_types = list(/obj/item/food/grown/carrot), tame_chance = 100, after_tame = CALLBACK(src, PROC_REF(on_tame)))
|
||||
ADD_TRAIT(src, TRAIT_SPACEWALK, INNATE_TRAIT)
|
||||
RegisterSignal(src, COMSIG_HOSTILE_PRE_ATTACKINGTARGET, PROC_REF(pre_attack))
|
||||
on_hit_overlay = mutable_appearance(icon, "[icon_state]_crying")
|
||||
|
||||
/mob/living/basic/eyeball/UnarmedAttack(atom/attack_target, proximity_flag, list/modifiers)
|
||||
. = ..()
|
||||
if(!.)
|
||||
return
|
||||
|
||||
if(!proximity_flag)
|
||||
return
|
||||
|
||||
if(istype(attack_target, /obj/item/food/grown/carrot))
|
||||
adjustBruteLoss(-5)
|
||||
to_chat(src, span_warning("You eat [attack_target]! It restores some health!"))
|
||||
qdel(attack_target)
|
||||
return TRUE
|
||||
|
||||
/mob/living/basic/eyeball/attackby(obj/item/weapon, mob/living/carbon/human/user, list/modifiers)
|
||||
. = ..()
|
||||
if(!weapon.force && !user.combat_mode)
|
||||
return
|
||||
if(crying)
|
||||
return
|
||||
change_crying_state()
|
||||
addtimer(CALLBACK(src, PROC_REF(change_crying_state)), 10 SECONDS) //cry for 10 seconds then remove
|
||||
|
||||
/mob/living/basic/eyeball/proc/change_crying_state()
|
||||
crying = !crying
|
||||
if(crying)
|
||||
add_overlay(on_hit_overlay)
|
||||
return
|
||||
cut_overlay(on_hit_overlay)
|
||||
|
||||
|
||||
/mob/living/basic/eyeball/proc/pre_attack(mob/living/eyeball, atom/target)
|
||||
SIGNAL_HANDLER
|
||||
|
||||
if(!ishuman(target))
|
||||
return
|
||||
|
||||
var/mob/living/carbon/human_target = target
|
||||
var/obj/item/organ/internal/eyes/eyes = human_target.get_organ_slot(ORGAN_SLOT_EYES)
|
||||
if(!eyes)
|
||||
return
|
||||
if(eyes.damage < 10)
|
||||
return
|
||||
heal_eye_damage(human_target, eyes)
|
||||
return COMPONENT_HOSTILE_NO_ATTACK
|
||||
|
||||
|
||||
/mob/living/basic/eyeball/proc/heal_eye_damage(mob/living/target, obj/item/organ/internal/eyes/eyes)
|
||||
if(!COOLDOWN_FINISHED(src, eye_healing))
|
||||
return
|
||||
to_chat(target, span_warning("[src] seems to be healing your [eyes.zone]!"))
|
||||
eyes.apply_organ_damage(-1 * healing_factor)
|
||||
new /obj/effect/temp_visual/heal(get_turf(target), COLOR_HEALING_CYAN)
|
||||
befriend(target)
|
||||
COOLDOWN_START(src, eye_healing, 15 SECONDS)
|
||||
|
||||
/mob/living/basic/eyeball/proc/on_tame(mob/tamer)
|
||||
spin(spintime = 2 SECONDS, speed = 1)
|
||||
//become passive to the humens
|
||||
faction |= tamer.faction
|
||||
@@ -0,0 +1,40 @@
|
||||
/datum/action/cooldown/spell/pointed/death_glare
|
||||
name = "death glare"
|
||||
desc = "give a death stare to the victim"
|
||||
var/glare_outline = COLOR_DARK_RED
|
||||
spell_requirements = NONE
|
||||
cooldown_time = 10 SECONDS
|
||||
|
||||
/datum/action/cooldown/spell/pointed/death_glare/is_valid_target(atom/cast_on)
|
||||
if(!isliving(cast_on))
|
||||
to_chat(owner, span_warning("Only living things are affected by our glare!"))
|
||||
return FALSE
|
||||
var/mob/living/living_target = cast_on
|
||||
if(living_target.has_movespeed_modifier(/datum/movespeed_modifier/glare_slowdown))
|
||||
to_chat(owner, span_warning("This target is already affected by a glare!"))
|
||||
return FALSE
|
||||
if(!can_see(living_target, owner, 9))
|
||||
to_chat(owner, span_warning("This target cannot see our glare!"))
|
||||
return FALSE
|
||||
var/direction_to_compare = get_dir(living_target, owner)
|
||||
var/target_direction = living_target.dir
|
||||
if(direction_to_compare != target_direction)
|
||||
to_chat(owner, span_warning("This target is facing away from us!"))
|
||||
return FALSE
|
||||
|
||||
return TRUE
|
||||
|
||||
/datum/action/cooldown/spell/pointed/death_glare/cast(mob/living/cast_on)
|
||||
. = ..()
|
||||
cast_on.add_filter("glare", 2, list("type" = "outline", "color" = glare_outline, "size" = 1))
|
||||
cast_on.add_movespeed_modifier(/datum/movespeed_modifier/glare_slowdown)
|
||||
to_chat(cast_on, span_warning("You feel something watching you..."))
|
||||
addtimer(CALLBACK(src, PROC_REF(remove_effect), cast_on), 5 SECONDS)
|
||||
return TRUE
|
||||
|
||||
/datum/action/cooldown/spell/pointed/death_glare/proc/remove_effect(mob/living/cast_on)
|
||||
cast_on.remove_movespeed_modifier(/datum/movespeed_modifier/glare_slowdown)
|
||||
cast_on.remove_filter("glare")
|
||||
|
||||
/datum/movespeed_modifier/glare_slowdown
|
||||
multiplicative_slowdown = 3
|
||||
@@ -0,0 +1,94 @@
|
||||
/datum/ai_behavior/find_the_blind
|
||||
|
||||
/datum/ai_behavior/find_the_blind/perform(seconds_per_tick, datum/ai_controller/controller, blind_key, threshold_key)
|
||||
. = ..()
|
||||
|
||||
var/mob/living_pawn = controller.pawn
|
||||
var/list/blind_list = list()
|
||||
var/eye_damage_threshold = controller.blackboard[threshold_key]
|
||||
if(!eye_damage_threshold)
|
||||
finish_action(controller, FALSE)
|
||||
return
|
||||
for(var/mob/living/carbon/blind in oview(9, living_pawn))
|
||||
var/obj/item/organ/internal/eyes/eyes = blind.get_organ_slot(ORGAN_SLOT_EYES)
|
||||
if(isnull(eyes))
|
||||
continue
|
||||
if(eyes.damage < eye_damage_threshold)
|
||||
continue
|
||||
blind_list += blind
|
||||
|
||||
if(!length(blind_list))
|
||||
finish_action(controller, FALSE)
|
||||
return
|
||||
|
||||
controller.set_blackboard_key(blind_key, pick(blind_list))
|
||||
finish_action(controller, TRUE)
|
||||
|
||||
/datum/ai_behavior/heal_eye_damage
|
||||
behavior_flags = AI_BEHAVIOR_REQUIRE_MOVEMENT | AI_BEHAVIOR_REQUIRE_REACH
|
||||
|
||||
/datum/ai_behavior/heal_eye_damage/setup(datum/ai_controller/controller, target_key)
|
||||
. = ..()
|
||||
var/mob/living/carbon/target = controller.blackboard[target_key]
|
||||
if(QDELETED(target))
|
||||
return FALSE
|
||||
set_movement_target(controller, target)
|
||||
|
||||
/datum/ai_behavior/heal_eye_damage/perform(seconds_per_tick, datum/ai_controller/controller, target_key)
|
||||
. = ..()
|
||||
|
||||
var/mob/living/carbon/target = controller.blackboard[target_key]
|
||||
var/mob/living/living_pawn = controller.pawn
|
||||
|
||||
if(QDELETED(target))
|
||||
finish_action(controller, FALSE, target_key)
|
||||
return
|
||||
var/obj/item/organ/internal/eyes/eyes = target.get_organ_slot(ORGAN_SLOT_EYES)
|
||||
var/datum/callback/callback = CALLBACK(living_pawn, TYPE_PROC_REF(/mob/living/basic/eyeball, heal_eye_damage), target, eyes)
|
||||
callback.Invoke()
|
||||
|
||||
finish_action(controller, TRUE, target_key)
|
||||
|
||||
/datum/ai_behavior/heal_eye_damage/finish_action(datum/ai_controller/controller, succeeded, target_key)
|
||||
. = ..()
|
||||
controller.clear_blackboard_key(target_key)
|
||||
|
||||
/datum/ai_behavior/targeted_mob_ability/glare_at_target
|
||||
behavior_flags = AI_BEHAVIOR_REQUIRE_MOVEMENT
|
||||
required_distance = 0
|
||||
|
||||
/datum/ai_behavior/targeted_mob_ability/glare_at_target/setup(datum/ai_controller/controller, ability_key, target_key)
|
||||
. = ..()
|
||||
var/atom/target = controller.blackboard[target_key]
|
||||
if (isnull(target))
|
||||
return FALSE
|
||||
|
||||
var/turf/turf_to_move_towards = get_step(target, target.dir)
|
||||
if(turf_to_move_towards.is_blocked_turf(ignore_atoms = list(controller.pawn)))
|
||||
return FALSE
|
||||
|
||||
if(isnull(turf_to_move_towards))
|
||||
return FALSE
|
||||
|
||||
set_movement_target(controller, turf_to_move_towards)
|
||||
|
||||
/datum/ai_behavior/targeted_mob_ability/glare_at_target/perform(seconds_per_tick, datum/ai_controller/controller, ability_key, target_key)
|
||||
var/datum/action/cooldown/ability = controller.blackboard[ability_key]
|
||||
var/mob/living/target = controller.blackboard[target_key]
|
||||
|
||||
if(QDELETED(ability) || QDELETED(target))
|
||||
finish_action(controller, FALSE, ability_key, target_key)
|
||||
return
|
||||
|
||||
var/direction_to_compare = get_dir(target, controller.pawn)
|
||||
var/target_direction = target.dir
|
||||
if(direction_to_compare != target_direction)
|
||||
finish_action(controller, FALSE, ability_key, target_key)
|
||||
return
|
||||
|
||||
var/result = ability.InterceptClickOn(controller.pawn, null, target)
|
||||
finish_action(controller, result, ability_key, target_key)
|
||||
|
||||
/datum/ai_behavior/hunt_target/unarmed_attack_target/carrot
|
||||
hunt_cooldown = 2 SECONDS
|
||||
always_reset_target = TRUE
|
||||
@@ -0,0 +1,56 @@
|
||||
/datum/ai_controller/basic_controller/eyeball
|
||||
blackboard = list(
|
||||
BB_TARGETTING_DATUM = new /datum/targetting_datum/basic/eyeball,
|
||||
BB_EYE_DAMAGE_THRESHOLD = 10,
|
||||
)
|
||||
|
||||
ai_movement = /datum/ai_movement/basic_avoidance
|
||||
idle_behavior = /datum/idle_behavior/idle_random_walk
|
||||
planning_subtrees = list(
|
||||
/datum/ai_planning_subtree/simple_find_target,
|
||||
/datum/ai_planning_subtree/targeted_mob_ability/glare,
|
||||
/datum/ai_planning_subtree/basic_melee_attack_subtree,
|
||||
/datum/ai_planning_subtree/heal_the_blind,
|
||||
/datum/ai_planning_subtree/find_and_hunt_target/carrot,
|
||||
)
|
||||
|
||||
/datum/ai_planning_subtree/heal_the_blind
|
||||
|
||||
/datum/ai_planning_subtree/heal_the_blind/SelectBehaviors(datum/ai_controller/controller, seconds_per_tick)
|
||||
var/mob/living/carbon/target = controller.blackboard[BB_BLIND_TARGET]
|
||||
|
||||
if(QDELETED(target))
|
||||
controller.queue_behavior(/datum/ai_behavior/find_the_blind, BB_BLIND_TARGET, BB_EYE_DAMAGE_THRESHOLD)
|
||||
return
|
||||
|
||||
controller.queue_behavior(/datum/ai_behavior/heal_eye_damage, BB_BLIND_TARGET)
|
||||
return SUBTREE_RETURN_FINISH_PLANNING
|
||||
|
||||
/datum/targetting_datum/basic/eyeball/can_attack(mob/living/owner, atom/target)
|
||||
. = ..()
|
||||
if(!.)
|
||||
return FALSE
|
||||
if(!ishuman(target))
|
||||
return TRUE
|
||||
var/mob/living/carbon/human_target = target
|
||||
if(human_target.is_blind())
|
||||
return FALSE
|
||||
var/eye_damage_threshold = owner.ai_controller.blackboard[BB_EYE_DAMAGE_THRESHOLD]
|
||||
if(!eye_damage_threshold)
|
||||
return TRUE
|
||||
var/obj/item/organ/internal/eyes/eyes = human_target.get_organ_slot(ORGAN_SLOT_EYES)
|
||||
if(eyes.damage > eye_damage_threshold) //we dont attack people with bad vision
|
||||
return FALSE
|
||||
|
||||
return can_see(target, owner, 9) //if the target cant see us dont attack him
|
||||
|
||||
/datum/ai_planning_subtree/targeted_mob_ability/glare
|
||||
ability_key = BB_GLARE_ABILITY
|
||||
use_ability_behaviour = /datum/ai_behavior/targeted_mob_ability/glare_at_target
|
||||
finish_planning = TRUE
|
||||
|
||||
/datum/ai_planning_subtree/find_and_hunt_target/carrot
|
||||
target_key = BB_LOW_PRIORITY_HUNTING_TARGET
|
||||
hunting_behavior = /datum/ai_behavior/hunt_target/unarmed_attack_target/carrot
|
||||
hunt_targets = list(/obj/item/food/grown/carrot)
|
||||
hunt_range = 6
|
||||
Reference in New Issue
Block a user