forked from Monkestation/Monkestation2.0
-
Notifications
You must be signed in to change notification settings - Fork 0
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
convert the eyeball a basic monster (tgstation#77411)
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. ![eyeballs pictures](https://github.com/tgstation/tgstation/assets/138636438/8933ea63-d339-474b-8c6e-90a222b74945) the eyeball now have more depth and character to his behavier. :cl: 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 /:cl:
- Loading branch information
1 parent
a683c02
commit 01e034a
Showing
10 changed files
with
339 additions
and
46 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
123 changes: 123 additions & 0 deletions
123
code/modules/mob/living/basic/space_fauna/eyeball/_eyeball.dm
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -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 |
40 changes: 40 additions & 0 deletions
40
code/modules/mob/living/basic/space_fauna/eyeball/eyeball_ability.dm
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -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 |
94 changes: 94 additions & 0 deletions
94
code/modules/mob/living/basic/space_fauna/eyeball/eyeball_ai_behavior.dm
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -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 |
56 changes: 56 additions & 0 deletions
56
code/modules/mob/living/basic/space_fauna/eyeball/eyeball_ai_subtree.dm
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -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 |
This file was deleted.
Oops, something went wrong.
Binary file not shown.
Oops, something went wrong.