mirror of
https://github.com/ParadiseSS13/Paradise.git
synced 2026-08-28 22:47:59 +01:00
Moves possessed objects to basic mobs (#29851)
* Moves possessed objects to basic mobs * Linters * Merge conflict resolution --------- Signed-off-by: PollardTheDragon <144391971+PollardTheDragon@users.noreply.github.com>
This commit is contained in:
@@ -0,0 +1,40 @@
|
||||
/datum/ai_behavior/swirl_around_target
|
||||
behavior_flags = AI_BEHAVIOR_REQUIRE_MOVEMENT | AI_BEHAVIOR_MOVE_AND_PERFORM
|
||||
required_distance = 0
|
||||
/// chance to swirl
|
||||
var/swirl_chance = 60
|
||||
|
||||
/datum/ai_behavior/swirl_around_target/setup(datum/ai_controller/controller, target_key)
|
||||
. = ..()
|
||||
var/atom/target = controller.blackboard[target_key]
|
||||
if(QDELETED(target))
|
||||
return FALSE
|
||||
set_movement_target(controller, target)
|
||||
|
||||
/datum/ai_behavior/swirl_around_target/perform(seconds_per_tick, datum/ai_controller/controller, target_key)
|
||||
var/atom/target = controller.blackboard[target_key]
|
||||
var/mob/living/living_pawn = controller.pawn
|
||||
|
||||
if(QDELETED(target))
|
||||
return AI_BEHAVIOR_INSTANT | AI_BEHAVIOR_SUCCEEDED
|
||||
|
||||
if(get_dist(target, living_pawn) > 1)
|
||||
set_movement_target(controller, target)
|
||||
return AI_BEHAVIOR_DELAY
|
||||
|
||||
if(!SPT_PROB(swirl_chance, seconds_per_tick))
|
||||
return AI_BEHAVIOR_DELAY
|
||||
|
||||
var/list/possible_turfs = list()
|
||||
|
||||
for(var/turf/possible_turf in oview(2, target))
|
||||
if(possible_turf.is_blocked_turf(source_atom = living_pawn))
|
||||
continue
|
||||
possible_turfs += possible_turf
|
||||
|
||||
if(!length(possible_turfs))
|
||||
return AI_BEHAVIOR_DELAY
|
||||
|
||||
if(isnull(controller.movement_target_source) || controller.movement_target_source == type)
|
||||
set_movement_target(controller, pick(possible_turfs))
|
||||
return AI_BEHAVIOR_DELAY
|
||||
@@ -0,0 +1,7 @@
|
||||
/datum/ai_planning_subtree/swirl_around_target
|
||||
/// Variable to store target in
|
||||
var/target_key = BB_BASIC_MOB_CURRENT_TARGET
|
||||
|
||||
/datum/ai_planning_subtree/swirl_around_target/select_behaviors(datum/ai_controller/controller, seconds_per_tick)
|
||||
. = ..()
|
||||
controller.queue_behavior(/datum/ai_behavior/swirl_around_target, target_key)
|
||||
@@ -40,6 +40,7 @@
|
||||
contains_xeno_organ = TRUE
|
||||
ignore_generic_organs = TRUE
|
||||
surgery_container = /datum/xenobiology_surgery_container/revenant
|
||||
faction = list("revenant")
|
||||
|
||||
/// The revenant's idle icon
|
||||
var/icon_idle = "revenant_idle"
|
||||
|
||||
@@ -369,43 +369,32 @@
|
||||
/// Handles making an object haunted and setting it up to attack
|
||||
/datum/spell/aoe/revenant/haunt_object/proc/make_spooky(obj/item/item_to_possess, mob/living/simple_animal/revenant/user)
|
||||
new /obj/effect/temp_visual/revenant(get_turf(item_to_possess)) // Thematic spooky visuals
|
||||
var/mob/living/simple_animal/possessed_object/possessed_object = new(item_to_possess) // Begin haunting object
|
||||
item_to_possess.throwforce = min(item_to_possess.throwforce + 5, 15) // Damage it should do? throwforce+5 or 15, whichever is lower
|
||||
var/mob/living/basic/possessed_object/revenant/possessed_object = new(item_to_possess) // Begin haunting object
|
||||
set_outline(possessed_object)
|
||||
possessed_object.maxHealth = 100 // Double the regular HP of possessed objects
|
||||
possessed_object.health = 100
|
||||
possessed_object.escape_chance = 100 // We cannot be contained
|
||||
ADD_TRAIT(possessed_object, TRAIT_DODGE_ALL_OBJECTS, "Revenant")
|
||||
addtimer(CALLBACK(src, PROC_REF(begin_poltergheist), possessed_object, user), 1 SECONDS, TIMER_UNIQUE) // Short warm-up for floaty ambience
|
||||
addtimer(CALLBACK(possessed_object, TYPE_PROC_REF(/mob/living/basic/possessed_object, death)), 70 SECONDS, TIMER_UNIQUE) // De-haunt the object
|
||||
|
||||
addtimer(CALLBACK(src, PROC_REF(attack__legacy__attackchain), possessed_object, user), 1 SECONDS, TIMER_UNIQUE) // Short warm-up for floaty ambience
|
||||
attack_timers.Add(addtimer(CALLBACK(src, PROC_REF(attack__legacy__attackchain), possessed_object, user), 4 SECONDS, TIMER_UNIQUE|TIMER_LOOP|TIMER_STOPPABLE)) // 5 second looping attacks
|
||||
addtimer(CALLBACK(possessed_object, TYPE_PROC_REF(/mob/living/simple_animal/possessed_object, death)), 70 SECONDS, TIMER_UNIQUE) // De-haunt the object
|
||||
/// Gives it AI
|
||||
/datum/spell/aoe/revenant/haunt_object/proc/begin_poltergheist(mob/living/basic/possessed_object/possessed_object, mob/living/simple_animal/revenant/user)
|
||||
possessed_object.ai_controller = new /datum/ai_controller/basic_controller/revenant(possessed_object)
|
||||
|
||||
/// Handles finding a valid target and throwing us at it
|
||||
/datum/spell/aoe/revenant/haunt_object/proc/attack__legacy__attackchain(mob/living/simple_animal/possessed_object/possessed_object, mob/living/simple_animal/revenant/user)
|
||||
var/list/potential_victims = list()
|
||||
for(var/turf/turf_to_search in spiral_range_turfs(aoe_range, get_turf(possessed_object)))
|
||||
for(var/mob/living/potential_victim in turf_to_search)
|
||||
if(QDELETED(possessed_object) || !can_see(possessed_object, potential_victim, aoe_range)) // You can't see me
|
||||
continue
|
||||
if(potential_victim.stat != CONSCIOUS) // Don't kill our precious essence-filled sleepy mobs
|
||||
continue
|
||||
if(istype(potential_victim, user) || istype(potential_victim, possessed_object))
|
||||
continue
|
||||
potential_victims.Add(potential_victim)
|
||||
/datum/ai_controller/basic_controller/revenant
|
||||
blackboard = list(
|
||||
BB_TARGETING_STRATEGY = /datum/targeting_strategy/basic,
|
||||
)
|
||||
|
||||
potential_victims.Cut((length(potential_victims) * 0.8) + 1.2) // Only consider the people near us
|
||||
|
||||
if(!length(potential_victims))
|
||||
possessed_object.possessed_item.throwforce = min(possessed_object.possessed_item.throwforce + 5, 15) // If an item is stood still for a while it can gather power
|
||||
set_outline(possessed_object)
|
||||
return
|
||||
|
||||
var/mob/living/victim = pick(potential_victims)
|
||||
possessed_object.throw_at(victim, aoe_range, 2, user, dodgeable = FALSE)
|
||||
ai_movement = /datum/ai_movement/basic_avoidance
|
||||
idle_behavior = null
|
||||
planning_subtrees = list(
|
||||
/datum/ai_planning_subtree/simple_find_target,
|
||||
/datum/ai_planning_subtree/attack_obstacle_in_path,
|
||||
/datum/ai_planning_subtree/swirl_around_target,
|
||||
/datum/ai_planning_subtree/basic_melee_attack_subtree,
|
||||
)
|
||||
|
||||
/// Sets the glow on the haunted object, scales up based on throwforce
|
||||
/datum/spell/aoe/revenant/haunt_object/proc/set_outline(mob/living/simple_animal/possessed_object/possessed_object)
|
||||
/datum/spell/aoe/revenant/haunt_object/proc/set_outline(mob/living/basic/possessed_object/possessed_object)
|
||||
possessed_object.remove_filter("haunt_glow")
|
||||
var/outline_size = min((possessed_object.possessed_item.throwforce / 15) * 3, 3)
|
||||
possessed_object.add_filter("haunt_glow", 2, list("type" = "outline", "color" = "#7A4FA9", "size" = outline_size)) // Give it spooky purple outline
|
||||
|
||||
@@ -933,7 +933,7 @@ GLOBAL_VAR_INIT(gamma_ship_location, 1) // 0 = station , 1 = space
|
||||
if(!frommob || !toitem) //make sure the mobs don't go away while we waited for a response
|
||||
return TRUE
|
||||
|
||||
var/mob/living/simple_animal/possessed_object/tomob = new(toitem)
|
||||
var/mob/living/basic/possessed_object/tomob = new(toitem)
|
||||
|
||||
message_admins("<span class='adminnotice'>[key_name_admin(usr)] has put [frommob.ckey] in control of [tomob.name].</span>")
|
||||
log_admin("[key_name(usr)] stuffed [frommob.ckey] into [tomob.name].")
|
||||
|
||||
+49
-25
@@ -1,29 +1,27 @@
|
||||
/mob/living/simple_animal/possessed_object
|
||||
/mob/living/basic/possessed_object
|
||||
name = "possessed object"
|
||||
var/spirit_name = "mysterious force" // What we call ourselves in attack messages.
|
||||
mob_biotypes = MOB_SPIRIT
|
||||
health = 50
|
||||
maxHealth = 50
|
||||
|
||||
pass_flags = PASSTABLE // Floating past tables is pretty damn spooky.
|
||||
status_flags = null // No canpush to prevent grabs ...
|
||||
density = FALSE // ... But a density of 0 means we won't be blocking anyone's way.
|
||||
healable = FALSE // Animated with SPACE NECROMANCY, mere mortal medicines cannot heal such an object.
|
||||
wander = FALSE // These things probably ought to never be AI controlled, but in the event they are probably shouldn't wander.
|
||||
|
||||
universal_speak = TRUE // Tell the humans spooky things about the afterlife
|
||||
ai_controller = null // We don't give this mob a controller, as usually they're player controlled. Rev versions get a special controller.
|
||||
speak_emote = list("mumbles", "moans", "whispers", "laments", "screeches")
|
||||
|
||||
no_spin_thrown = TRUE
|
||||
del_on_death = TRUE
|
||||
basic_mob_flags = DEL_ON_DEATH
|
||||
weather_immunities = list("ash")
|
||||
|
||||
/// The probability % of us escaping if stuffed into a bag/toolbox/etc
|
||||
var/escape_chance = 10
|
||||
/// What is the actual item we are "possessing"
|
||||
var/obj/item/possessed_item
|
||||
/// Is this item possessed by a revenant?
|
||||
var/revenant_possessed = FALSE
|
||||
|
||||
/mob/living/simple_animal/possessed_object/examine(mob/user)
|
||||
/mob/living/basic/possessed_object/examine(mob/user)
|
||||
. = possessed_item.examine(user)
|
||||
if(health > (maxHealth / 30))
|
||||
. += "<span class='warning'>[src] appears to be floating without any support!</span>"
|
||||
@@ -31,17 +29,17 @@
|
||||
. += "<span class='warning'>[src] appears to be having trouble staying afloat!</span>"
|
||||
|
||||
|
||||
/mob/living/simple_animal/possessed_object/do_attack_animation(atom/A, visual_effect_icon, used_item, no_effect)
|
||||
/mob/living/basic/possessed_object/do_attack_animation(atom/A, visual_effect_icon, used_item, no_effect)
|
||||
..()
|
||||
animate_ghostly_presence(src, -1, 20, 1) // Restart the floating animation after the attack animation, as it will be cancelled.
|
||||
|
||||
|
||||
/mob/living/simple_animal/possessed_object/start_pulling(atom/movable/AM, state, force = pull_force, show_message = FALSE) // Silly motherfuckers think they can pull things.
|
||||
/mob/living/basic/possessed_object/start_pulling(atom/movable/AM, state, force = pull_force, show_message = FALSE) // Silly motherfuckers think they can pull things.
|
||||
if(show_message)
|
||||
to_chat(src, "<span class='warning'>You are unable to pull [AM]!</span>")
|
||||
|
||||
|
||||
/mob/living/simple_animal/possessed_object/ghost() // Ghosting will return the object to normal, and will not disqualify the ghoster from various mid-round antag positions.
|
||||
/mob/living/basic/possessed_object/ghost() // Ghosting will return the object to normal, and will not disqualify the ghoster from various mid-round antag positions.
|
||||
var/response = tgui_alert(src, "End your possession of this object? (It will not stop you from respawning later)", "Are you sure you want to ghost?", list("Ghost", "Stay in body"))
|
||||
if(response != "Ghost")
|
||||
return
|
||||
@@ -50,7 +48,7 @@
|
||||
ghost.timeofdeath = world.time
|
||||
death(0) // Turn back into a regular object.
|
||||
|
||||
/mob/living/simple_animal/possessed_object/death(gibbed)
|
||||
/mob/living/basic/possessed_object/death(gibbed)
|
||||
if(can_die())
|
||||
ghostize(TRUE)
|
||||
// if gibbed, the item goes with the ghost
|
||||
@@ -62,7 +60,7 @@
|
||||
|
||||
return ..()
|
||||
|
||||
/mob/living/simple_animal/possessed_object/Life(seconds, times_fired)
|
||||
/mob/living/basic/possessed_object/Life(seconds, times_fired)
|
||||
..()
|
||||
|
||||
if(!possessed_item) // If we're a donut and someone's eaten us, for instance.
|
||||
@@ -86,12 +84,12 @@
|
||||
if(possessed_item.loc != src) //safety so the item doesn't somehow become detatched from us while doing this
|
||||
possessed_item.forceMove(src)
|
||||
|
||||
/mob/living/simple_animal/possessed_object/Login()
|
||||
/mob/living/basic/possessed_object/Login()
|
||||
..()
|
||||
to_chat(src, "<span class='notice'><b>Your spirit has entered [src] and possessed it.</b><br>You are able to do most things a humanoid would be able to do with a [src] in their hands.<br>If you want to end your ghostly possession, use the '<b>ghost</b>' verb, it won't penalize your ability to respawn.</span>")
|
||||
|
||||
|
||||
/mob/living/simple_animal/possessed_object/Initialize(mapload)
|
||||
/mob/living/basic/possessed_object/Initialize(mapload)
|
||||
. = ..()
|
||||
|
||||
if(!isitem(loc)) // Some silly motherfucker spawned us directly via the game panel.
|
||||
@@ -114,27 +112,31 @@
|
||||
throwforce = possessed_item.throwforce
|
||||
armour_penetration_flat = possessed_item.armour_penetration_flat
|
||||
armour_penetration_percentage = possessed_item.armour_penetration_percentage
|
||||
melee_damage_lower = max(0, possessed_item.force - 5)
|
||||
melee_damage_upper = possessed_item.force + 5
|
||||
|
||||
visible_message("<span class='notice'>[src] rises into the air and begins to float!</span>") // Inform those around us that shit's gettin' spooky.
|
||||
animate_ghostly_presence(src, -1, 20, 1)
|
||||
|
||||
|
||||
/mob/living/simple_animal/possessed_object/get_active_hand() // So that our attacks count as attacking with the item we've possessed.
|
||||
/mob/living/basic/possessed_object/get_active_hand() // So that our attacks count as attacking with the item we've possessed.
|
||||
if(revenant_possessed)
|
||||
return ..()
|
||||
return possessed_item
|
||||
|
||||
|
||||
/mob/living/simple_animal/possessed_object/IsAdvancedToolUser() // So we can shoot guns (Mostly ourselves), among other things.
|
||||
/mob/living/basic/possessed_object/IsAdvancedToolUser() // So we can shoot guns (Mostly ourselves), among other things.
|
||||
return TRUE
|
||||
|
||||
|
||||
/mob/living/simple_animal/possessed_object/get_access() // If we've possessed an ID card we've got access to lots of fun things!
|
||||
/mob/living/basic/possessed_object/get_access() // If we've possessed an ID card we've got access to lots of fun things!
|
||||
if(istype(possessed_item, /obj/item/card/id))
|
||||
var/obj/item/card/id/possessed_id = possessed_item
|
||||
. = possessed_id.access
|
||||
|
||||
|
||||
/mob/living/simple_animal/possessed_object/ClickOn(atom/A, params)
|
||||
if(client.click_intercept)
|
||||
/mob/living/basic/possessed_object/ClickOn(atom/A, params)
|
||||
if(client && client.click_intercept)
|
||||
client.click_intercept.InterceptClickOn(src, params, A)
|
||||
return
|
||||
|
||||
@@ -153,11 +155,15 @@
|
||||
forceMove(possessed_item.loc)
|
||||
possessed_item.forceMove(src)
|
||||
else // If we're inside a toolbox or something, we are inside the item rather than the item inside us. This is so people can see the item in the toolbox.
|
||||
forceMove( possessed_item )
|
||||
forceMove(possessed_item)
|
||||
|
||||
update_icon()
|
||||
|
||||
/mob/living/simple_animal/possessed_object/update_icon(update_pixel_xy = 0)
|
||||
/mob/living/basic/possessed_object/melee_attack(atom/target, list/modifiers, ignore_cooldown)
|
||||
. = ..()
|
||||
animate_ghostly_presence(src, -1, 20, 1)
|
||||
|
||||
/mob/living/basic/possessed_object/update_icon(update_pixel_xy = 0)
|
||||
name = possessed_item.name // Take on all the attributes of the item we've possessed.
|
||||
real_name = name
|
||||
desc = possessed_item.desc
|
||||
@@ -173,13 +179,31 @@
|
||||
set_opacity(possessed_item.opacity)
|
||||
return ..(NONE)
|
||||
|
||||
/mob/living/simple_animal/possessed_object/item_interaction(mob/living/user, obj/item/O, list/modifiers)
|
||||
/mob/living/basic/possessed_object/item_interaction(mob/living/user, obj/item/O, list/modifiers)
|
||||
if(istype(O, /obj/item/nullrod))
|
||||
visible_message("<span type='notice'>[O] dispels the spooky aura!</span>")
|
||||
death()
|
||||
|
||||
return ITEM_INTERACT_COMPLETE
|
||||
|
||||
/mob/living/simple_animal/possessed_object/throw_impact(atom/hit_atom, throwingdatum)
|
||||
//Don't call parent here as the mob isn't doing the hitting, technically
|
||||
/mob/living/basic/possessed_object/throw_impact(atom/hit_atom, throwingdatum)
|
||||
// Don't call parent here as the mob isn't doing the hitting, technically
|
||||
return possessed_item.throw_impact(hit_atom, throwingdatum)
|
||||
|
||||
/mob/living/basic/possessed_object/revenant
|
||||
maxHealth = 100
|
||||
health = 100
|
||||
melee_attack_cooldown_min = 4 SECONDS
|
||||
melee_attack_cooldown_max = 5 SECONDS
|
||||
faction = list("revenant")
|
||||
speed = -1
|
||||
a_intent = INTENT_HARM
|
||||
escape_chance = 100
|
||||
revenant_possessed = TRUE
|
||||
|
||||
/mob/living/basic/possessed_object/revenant/Initialize(mapload)
|
||||
. = ..()
|
||||
AddComponent(/datum/component/swarming)
|
||||
throwforce = min(possessed_item.throwforce + 5, 15) // Damage it should do? throwforce+5 or 15, whichever is lower
|
||||
melee_damage_lower = min(possessed_item.throwforce + 5, 15)
|
||||
melee_damage_upper = melee_damage_lower
|
||||
+3
-1
@@ -462,6 +462,7 @@
|
||||
#include "code\datums\ai\basic_mobs\basic_ai_behaviors\nearest_targeting.dm"
|
||||
#include "code\datums\ai\basic_mobs\basic_ai_behaviors\run_away_from_target.dm"
|
||||
#include "code\datums\ai\basic_mobs\basic_ai_behaviors\stop_and_stare.dm"
|
||||
#include "code\datums\ai\basic_mobs\basic_ai_behaviors\swirl_around.dm"
|
||||
#include "code\datums\ai\basic_mobs\basic_ai_behaviors\targeting.dm"
|
||||
#include "code\datums\ai\basic_mobs\basic_ai_behaviors\tipped_reaction.dm"
|
||||
#include "code\datums\ai\basic_mobs\basic_ai_behaviors\travel_towards.dm"
|
||||
@@ -475,6 +476,7 @@
|
||||
#include "code\datums\ai\basic_mobs\basic_subtrees\simple_attack_target.dm"
|
||||
#include "code\datums\ai\basic_mobs\basic_subtrees\simple_find_nearest_target_to_flee.dm"
|
||||
#include "code\datums\ai\basic_mobs\basic_subtrees\simple_find_target.dm"
|
||||
#include "code\datums\ai\basic_mobs\basic_subtrees\swirl_around_target.dm"
|
||||
#include "code\datums\ai\basic_mobs\basic_subtrees\stare_at_thing.dm"
|
||||
#include "code\datums\ai\basic_mobs\basic_subtrees\target_retaliate.dm"
|
||||
#include "code\datums\ai\basic_mobs\basic_subtrees\tip_reaction.dm"
|
||||
@@ -2408,6 +2410,7 @@
|
||||
#include "code\modules\mob\living\stat_states.dm"
|
||||
#include "code\modules\mob\living\taste.dm"
|
||||
#include "code\modules\mob\living\basic\basic_mob.dm"
|
||||
#include "code\modules\mob\living\basic\posessed_object.dm"
|
||||
#include "code\modules\mob\living\basic\farm_animals\cow.dm"
|
||||
#include "code\modules\mob\living\basic\farm_animals\deer.dm"
|
||||
#include "code\modules\mob\living\basic\farm_animals\deer_ai.dm"
|
||||
@@ -2597,7 +2600,6 @@
|
||||
#include "code\modules\mob\living\simple_animal\hide_action.dm"
|
||||
#include "code\modules\mob\living\simple_animal\parrot.dm"
|
||||
#include "code\modules\mob\living\simple_animal\parrot_stripping.dm"
|
||||
#include "code\modules\mob\living\simple_animal\posessed_object.dm"
|
||||
#include "code\modules\mob\living\simple_animal\shade.dm"
|
||||
#include "code\modules\mob\living\simple_animal\simple_animal.dm"
|
||||
#include "code\modules\mob\living\simple_animal\simple_animal_damage.dm"
|
||||
|
||||
Reference in New Issue
Block a user