mirror of
https://github.com/ParadiseSS13/Paradise.git
synced 2026-07-19 11:05:03 +01:00
Merge pull request #12157 from Fox-McCloud/simple-mob-update
TG Simple Mob Update
This commit is contained in:
@@ -155,6 +155,10 @@
|
||||
// /mob/living/carbon signals
|
||||
#define COMSIG_CARBON_SOUNDBANG "carbon_soundbang" //from base of mob/living/carbon/soundbang_act(): (list(intensity))
|
||||
|
||||
// /mob/living/simple_animal/hostile signals
|
||||
#define COMSIG_HOSTILE_ATTACKINGTARGET "hostile_attackingtarget"
|
||||
#define COMPONENT_HOSTILE_NO_ATTACK 1
|
||||
|
||||
// /obj signals
|
||||
#define COMSIG_OBJ_DECONSTRUCT "obj_deconstruct" //from base of obj/deconstruct(): (disassembled)
|
||||
#define COMSIG_OBJ_SETANCHORED "obj_setanchored" //called in /obj/structure/setAnchored(): (value)
|
||||
|
||||
@@ -13,6 +13,7 @@
|
||||
#define CONDUCT 32 // conducts electricity (metal etc.)
|
||||
#define ABSTRACT 64 // for all things that are technically items but used for various different stuff, made it 128 because it could conflict with other flags other way
|
||||
#define ON_BORDER 128 // item has priority to check when entering or leaving
|
||||
#define PREVENT_CLICK_UNDER 256
|
||||
|
||||
#define EARBANGPROTECT 1024
|
||||
|
||||
|
||||
@@ -18,6 +18,8 @@
|
||||
|
||||
#define ismecha(A) (istype(A, /obj/mecha))
|
||||
|
||||
#define isspacepod(A) (istype(A, /obj/spacepod))
|
||||
|
||||
#define iseffect(A) (istype(A, /obj/effect))
|
||||
|
||||
#define is_cleanable(A) (istype(A, /obj/effect/decal/cleanable) || istype(A, /obj/effect/rune)) //if something is cleanable
|
||||
|
||||
@@ -219,3 +219,5 @@
|
||||
#define hasorgans(A) (ishuman(A))
|
||||
|
||||
#define is_admin(user) (check_rights(R_ADMIN, 0, (user)) != 0)
|
||||
|
||||
#define SLEEP_CHECK_DEATH(X) sleep(X); if(QDELETED(src) || stat == DEAD) return;
|
||||
+27
-4
@@ -107,6 +107,9 @@
|
||||
if(next_move > world.time) // in the year 2000...
|
||||
return
|
||||
|
||||
if(!modifiers["catcher"] && A.IsObscured())
|
||||
return
|
||||
|
||||
if(istype(loc,/obj/mecha))
|
||||
if(!locate(/turf) in list(A,A.loc)) // Prevents inventory from being drilled
|
||||
return
|
||||
@@ -172,6 +175,24 @@
|
||||
|
||||
return
|
||||
|
||||
//Is the atom obscured by a PREVENT_CLICK_UNDER_1 object above it
|
||||
/atom/proc/IsObscured()
|
||||
if(!isturf(loc)) //This only makes sense for things directly on turfs for now
|
||||
return FALSE
|
||||
var/turf/T = get_turf_pixel(src)
|
||||
if(!T)
|
||||
return FALSE
|
||||
for(var/atom/movable/AM in T)
|
||||
if(AM.flags & PREVENT_CLICK_UNDER && AM.density && AM.layer > layer)
|
||||
return TRUE
|
||||
return FALSE
|
||||
|
||||
/turf/IsObscured()
|
||||
for(var/atom/movable/AM in src)
|
||||
if(AM.flags & PREVENT_CLICK_UNDER && AM.density)
|
||||
return TRUE
|
||||
return FALSE
|
||||
|
||||
// Default behavior: ignore double clicks, consider them normal clicks instead
|
||||
/mob/proc/DblClickOn(var/atom/A, var/params)
|
||||
return
|
||||
@@ -399,8 +420,8 @@
|
||||
dir = direction
|
||||
|
||||
/obj/screen/click_catcher
|
||||
icon = 'icons/mob/screen_full.dmi'
|
||||
icon_state = "passage0"
|
||||
icon = 'icons/mob/screen_gen.dmi'
|
||||
icon_state = "catcher"
|
||||
plane = CLICKCATCHER_PLANE
|
||||
mouse_opacity = MOUSE_OPACITY_OPAQUE
|
||||
screen_loc = "CENTER"
|
||||
@@ -430,5 +451,7 @@
|
||||
C.swap_hand()
|
||||
else
|
||||
var/turf/T = params2turf(modifiers["screen-loc"], get_turf(usr))
|
||||
T.Click(location, control, params)
|
||||
return 1
|
||||
params += "&catcher=1"
|
||||
if(T)
|
||||
T.Click(location, control, params)
|
||||
. = 1
|
||||
@@ -158,9 +158,9 @@
|
||||
////CTRL CLICK FOR SWARMERS AND SWARMER_ACT()'S////
|
||||
/mob/living/simple_animal/hostile/swarmer/AttackingTarget()
|
||||
if(!isliving(target))
|
||||
target.swarmer_act(src)
|
||||
return target.swarmer_act(src)
|
||||
else
|
||||
..()
|
||||
return ..()
|
||||
|
||||
/mob/living/simple_animal/hostile/swarmer/CtrlClickOn(atom/A)
|
||||
face_atom(A)
|
||||
@@ -352,11 +352,11 @@
|
||||
|
||||
/obj/structure/lattice/catwalk/swarmer_catwalk/swarmer_act(mob/living/simple_animal/hostile/swarmer/S)
|
||||
to_chat(S, "<span class='warning'>We have created these for our own benefit. Aborting.</span>")
|
||||
return FALSE
|
||||
return FALSE
|
||||
|
||||
/obj/structure/shuttle/engine/swarmer_act(mob/living/simple_animal/hostile/swarmer/S)
|
||||
to_chat(S, "<span class='warning'>This shuttle may be important to us later. Aborting.</span>")
|
||||
return FALSE
|
||||
return FALSE
|
||||
|
||||
////END CTRL CLICK FOR SWARMERS////
|
||||
|
||||
|
||||
@@ -123,7 +123,7 @@
|
||||
med_hud_set_health()
|
||||
med_hud_set_status()
|
||||
|
||||
/mob/living/simple_animal/hostile/guardian/adjustHealth(amount) //The spirit is invincible, but passes on damage to the summoner
|
||||
/mob/living/simple_animal/hostile/guardian/adjustHealth(amount, updating_health = TRUE) //The spirit is invincible, but passes on damage to the summoner
|
||||
var/damage = amount * damage_transfer
|
||||
if(summoner)
|
||||
if(loc == summoner)
|
||||
|
||||
@@ -26,11 +26,12 @@
|
||||
stat(null, "Stealth Cooldown Remaining: [max(round((stealthcooldown - world.time)*0.1, 0.1), 0)] seconds")
|
||||
|
||||
/mob/living/simple_animal/hostile/guardian/assassin/AttackingTarget()
|
||||
..()
|
||||
if(toggle && (isliving(target) || istype(target, /obj/structure/window) || istype(target, /obj/structure/grille)))
|
||||
ToggleMode(1)
|
||||
. = ..()
|
||||
if(.)
|
||||
if(toggle && (isliving(target) || istype(target, /obj/structure/window) || istype(target, /obj/structure/grille)))
|
||||
ToggleMode(1)
|
||||
|
||||
/mob/living/simple_animal/hostile/guardian/assassin/adjustHealth(amount, updating_health = TRUE, forced = FALSE)
|
||||
/mob/living/simple_animal/hostile/guardian/assassin/adjustHealth(amount, updating_health = TRUE)
|
||||
. = ..()
|
||||
if(. > 0 && toggle)
|
||||
ToggleMode(1)
|
||||
|
||||
@@ -28,9 +28,9 @@
|
||||
toggle = TRUE
|
||||
|
||||
/mob/living/simple_animal/hostile/guardian/fire/AttackingTarget()
|
||||
..()
|
||||
. = ..()
|
||||
if(toggle)
|
||||
if(ishuman(target) && !summoner)
|
||||
if(. && ishuman(target) && !summoner)
|
||||
spawn(0)
|
||||
new /obj/effect/hallucination/delusion(target.loc, target, force_kind = "custom", duration = 200, skip_nearby = 0, custom_icon = icon_state, custom_icon_file = icon)
|
||||
else
|
||||
|
||||
@@ -43,7 +43,7 @@
|
||||
stat(null, "Bluespace Beacon Cooldown Remaining: [max(round((beacon_cooldown - world.time)*0.1, 0.1), 0)] seconds")
|
||||
|
||||
/mob/living/simple_animal/hostile/guardian/healer/AttackingTarget()
|
||||
..()
|
||||
. = ..()
|
||||
if(toggle == TRUE)
|
||||
if(loc == summoner)
|
||||
to_chat(src, "<span class='danger'>You must be manifested to heal!</span>")
|
||||
|
||||
@@ -19,8 +19,8 @@
|
||||
var/successfulshocks = 0
|
||||
|
||||
/mob/living/simple_animal/hostile/guardian/beam/AttackingTarget()
|
||||
..()
|
||||
if(isliving(target) && target != src && target != summoner)
|
||||
. = ..()
|
||||
if(. && isliving(target) && target != src && target != summoner)
|
||||
cleardeletedchains()
|
||||
for(var/chain in enemychains)
|
||||
var/datum/beam/B = chain
|
||||
|
||||
@@ -11,10 +11,9 @@
|
||||
melee_damage_upper = 10
|
||||
damage_transfer = 0.9
|
||||
projectiletype = /obj/item/projectile/guardian
|
||||
ranged_cooldown_time = 10
|
||||
ranged_cooldown_time = 1 //fast!
|
||||
projectilesound = 'sound/effects/hit_on_shattered_glass.ogg'
|
||||
ranged = 1
|
||||
rapid = 1
|
||||
range = 13
|
||||
lighting_alpha = LIGHTING_PLANE_ALPHA_MOSTLY_INVISIBLE
|
||||
see_in_dark = 8
|
||||
|
||||
@@ -19,7 +19,7 @@
|
||||
battlecry = input
|
||||
|
||||
/mob/living/simple_animal/hostile/guardian/punch/AttackingTarget()
|
||||
..()
|
||||
. = ..()
|
||||
if(iscarbon(target) && target != summoner)
|
||||
if(length(battlecry) > 11)//no more then 11 letters in a battle cry.
|
||||
visible_message("<span class='danger'>[src] punches [target]!</span>")
|
||||
|
||||
@@ -28,7 +28,7 @@
|
||||
melee_damage_upper = 20
|
||||
see_in_dark = 8
|
||||
lighting_alpha = LIGHTING_PLANE_ALPHA_MOSTLY_INVISIBLE
|
||||
idle_vision_range = 1 // Only attack when target is close
|
||||
vision_range = 1 // Only attack when target is close
|
||||
wander = 0
|
||||
attacktext = "glomps"
|
||||
attack_sound = 'sound/effects/blobattack.ogg'
|
||||
@@ -54,7 +54,7 @@
|
||||
. = ..()
|
||||
AddSpell(new /obj/effect/proc_holder/spell/targeted/smoke)
|
||||
AddSpell(new /obj/effect/proc_holder/spell/targeted/forcewall)
|
||||
|
||||
|
||||
/mob/living/simple_animal/hostile/morph/examine(mob/user)
|
||||
if(morphed)
|
||||
if(form)
|
||||
@@ -153,7 +153,7 @@
|
||||
restore()
|
||||
|
||||
/mob/living/simple_animal/hostile/morph/LoseAggro()
|
||||
vision_range = idle_vision_range
|
||||
vision_range = initial(vision_range)
|
||||
|
||||
/mob/living/simple_animal/hostile/morph/AIShouldSleep(var/list/possible_targets)
|
||||
. = ..()
|
||||
@@ -179,4 +179,4 @@
|
||||
if(do_after(src, 20, target = I))
|
||||
eat(I)
|
||||
return
|
||||
target.attack_animal(src)
|
||||
return ..()
|
||||
|
||||
@@ -85,7 +85,7 @@
|
||||
/mob/living/simple_animal/revenant/narsie_act()
|
||||
return //most humans will now be either bones or harvesters, but we're still un-alive.
|
||||
|
||||
/mob/living/simple_animal/revenant/adjustHealth(amount)
|
||||
/mob/living/simple_animal/revenant/adjustHealth(amount, updating_health = TRUE)
|
||||
if(!revealed)
|
||||
return
|
||||
essence = max(0, essence-amount)
|
||||
|
||||
@@ -10,6 +10,7 @@
|
||||
power_channel = ENVIRON
|
||||
max_integrity = 350
|
||||
armor = list(melee = 30, bullet = 30, laser = 20, energy = 20, bomb = 10, bio = 100, rad = 100)
|
||||
flags = PREVENT_CLICK_UNDER
|
||||
var/closingLayer = CLOSED_DOOR_LAYER
|
||||
var/visible = 1
|
||||
var/operating = FALSE
|
||||
|
||||
@@ -140,6 +140,15 @@
|
||||
..()
|
||||
animate(src, alpha = 0, time = duration)
|
||||
|
||||
/obj/effect/temp_visual/decoy/fading/threesecond
|
||||
duration = 40
|
||||
|
||||
/obj/effect/temp_visual/decoy/fading/fivesecond
|
||||
duration = 50
|
||||
|
||||
/obj/effect/temp_visual/decoy/fading/halfsecond
|
||||
duration = 5
|
||||
|
||||
/obj/effect/temp_visual/fire
|
||||
icon = 'icons/goonstation/effects/fire.dmi'
|
||||
icon_state = "3"
|
||||
|
||||
@@ -579,6 +579,7 @@ var/global/wcCommon = pick(list("#379963", "#0d8395", "#58b5c3", "#49e46e", "#8f
|
||||
dir = FULLTILE_WINDOW_DIR
|
||||
level = 3
|
||||
fulltile = TRUE
|
||||
flags = PREVENT_CLICK_UNDER
|
||||
|
||||
/obj/structure/window/full/basic
|
||||
desc = "It looks thin and flimsy. A few knocks with... anything, really should shatter it."
|
||||
@@ -675,6 +676,7 @@ obj/structure/window/full/reinforced/ice
|
||||
dir = FULLTILE_WINDOW_DIR
|
||||
max_integrity = 200
|
||||
fulltile = TRUE
|
||||
flags = PREVENT_CLICK_UNDER
|
||||
reinf = TRUE
|
||||
heat_resistance = 1600
|
||||
armor = list("melee" = 50, "bullet" = 0, "laser" = 0, "energy" = 0, "bomb" = 50, "bio" = 100, "rad" = 100)
|
||||
@@ -734,6 +736,7 @@ obj/structure/window/full/reinforced/ice
|
||||
smooth = SMOOTH_TRUE
|
||||
canSmoothWith = null
|
||||
fulltile = TRUE
|
||||
flags = PREVENT_CLICK_UNDER
|
||||
dir = FULLTILE_WINDOW_DIR
|
||||
max_integrity = 120
|
||||
level = 3
|
||||
|
||||
@@ -77,6 +77,7 @@
|
||||
dir = FULLTILE_WINDOW_DIR
|
||||
max_integrity = 100
|
||||
fulltile = TRUE
|
||||
flags = PREVENT_CLICK_UNDER
|
||||
reinf = TRUE
|
||||
heat_resistance = 1600
|
||||
armor = list("melee" = 50, "bullet" = 0, "laser" = 0, "energy" = 0, "bomb" = 50, "bio" = 100, "rad" = 100)
|
||||
@@ -296,7 +297,7 @@
|
||||
name = "air flow blocker"
|
||||
resistance_flags = INDESTRUCTIBLE | LAVA_PROOF | FIRE_PROOF
|
||||
unacidable = TRUE
|
||||
invisibility = INVISIBILITY_ABSTRACT
|
||||
invisibility = INVISIBILITY_ABSTRACT
|
||||
|
||||
//Signs
|
||||
/obj/structure/sign/mining
|
||||
|
||||
@@ -380,7 +380,7 @@
|
||||
medsensor.add_hud_to(src)
|
||||
|
||||
/mob/living/simple_animal/hostile/lightgeist/AttackingTarget()
|
||||
..()
|
||||
. = ..()
|
||||
if(isliving(target) && target != src)
|
||||
var/mob/living/L = target
|
||||
if(L.stat < DEAD)
|
||||
|
||||
@@ -15,7 +15,6 @@
|
||||
a_intent = INTENT_HARM
|
||||
atmos_requirements = list("min_oxy" = 0, "max_oxy" = 0, "min_tox" = 0, "max_tox" = 0, "min_co2" = 0, "max_co2" = 0, "min_n2" = 0, "max_n2" = 0)
|
||||
minbodytemp = 0
|
||||
idle_vision_range = 5
|
||||
move_to_delay = 10
|
||||
health = 125
|
||||
maxHealth = 125
|
||||
@@ -145,7 +144,7 @@
|
||||
|
||||
/mob/living/simple_animal/hostile/mining_drone/proc/SetCollectBehavior()
|
||||
mode = MINEDRONE_COLLECT
|
||||
idle_vision_range = 9
|
||||
vision_range = 9
|
||||
search_objects = 2
|
||||
wander = TRUE
|
||||
ranged = FALSE
|
||||
@@ -156,7 +155,7 @@
|
||||
|
||||
/mob/living/simple_animal/hostile/mining_drone/proc/SetOffenseBehavior()
|
||||
mode = MINEDRONE_ATTACK
|
||||
idle_vision_range = 7
|
||||
vision_range = 7
|
||||
search_objects = 0
|
||||
wander = FALSE
|
||||
ranged = TRUE
|
||||
@@ -192,7 +191,7 @@
|
||||
for(var/obj/item/stack/ore/O in contents)
|
||||
O.forceMove(drop_location())
|
||||
|
||||
/mob/living/simple_animal/hostile/mining_drone/adjustHealth(amount)
|
||||
/mob/living/simple_animal/hostile/mining_drone/adjustHealth(amount, updating_health = TRUE)
|
||||
if(mode != MINEDRONE_ATTACK && amount > 0)
|
||||
SetOffenseBehavior()
|
||||
. = ..()
|
||||
|
||||
@@ -34,9 +34,6 @@
|
||||
|
||||
handcrafting = new()
|
||||
|
||||
var/mob/M = src
|
||||
faction |= "\ref[M]" //what
|
||||
|
||||
// Set up DNA.
|
||||
if(dna)
|
||||
dna.ready_dna(src)
|
||||
|
||||
@@ -65,8 +65,6 @@
|
||||
var/ventcrawler = 0 //Determines if the mob can go through the vents.
|
||||
var/has_fine_manipulation = 1 // Can use small items.
|
||||
|
||||
var/mob/living/list/ignored_by = list() // list of mobs that will ignore this species
|
||||
|
||||
var/list/allowed_consumed_mobs = list() //If a species can consume mobs, put the type of mobs it can consume here.
|
||||
|
||||
var/list/species_traits = list()
|
||||
|
||||
@@ -8,8 +8,6 @@
|
||||
|
||||
unarmed_type = /datum/unarmed_attack/claws
|
||||
|
||||
ignored_by = list(/mob/living/simple_animal/hostile/faithless)
|
||||
|
||||
blood_color = "#CCCCCC"
|
||||
flesh_color = "#AAAAAA"
|
||||
has_organ = list(
|
||||
@@ -51,12 +49,14 @@
|
||||
if(grant_vision_toggle)
|
||||
vision_toggle = new
|
||||
vision_toggle.Grant(H)
|
||||
H.faction |= "faithless"
|
||||
|
||||
/datum/species/shadow/on_species_loss(mob/living/carbon/human/H)
|
||||
..()
|
||||
if(grant_vision_toggle && vision_toggle)
|
||||
H.vision_type = null
|
||||
vision_toggle.Remove(H)
|
||||
H.faction -= "faithless"
|
||||
|
||||
/datum/species/shadow/handle_life(mob/living/carbon/human/H)
|
||||
var/light_amount = 0
|
||||
|
||||
@@ -2,6 +2,7 @@
|
||||
. = ..()
|
||||
var/datum/atom_hud/data/human/medical/advanced/medhud = huds[DATA_HUD_MEDICAL_ADVANCED]
|
||||
medhud.add_to_hud(src)
|
||||
faction += "\ref[src]"
|
||||
|
||||
/mob/living/prepare_huds()
|
||||
..()
|
||||
@@ -256,10 +257,10 @@
|
||||
death()
|
||||
to_chat(src, "<span class='notice'>You have given up life and succumbed to death.</span>")
|
||||
|
||||
|
||||
|
||||
/mob/living/proc/InCritical()
|
||||
return (health < HEALTH_THRESHOLD_CRIT && health > HEALTH_THRESHOLD_DEAD && stat == UNCONSCIOUS)
|
||||
|
||||
|
||||
|
||||
/mob/living/ex_act(severity)
|
||||
..()
|
||||
|
||||
@@ -1,10 +1,26 @@
|
||||
/mob/living/simple_animal/attackby(obj/item/O, mob/living/user)
|
||||
if(can_collar && !collar && istype(O, /obj/item/clothing/accessory/petcollar))
|
||||
var/obj/item/clothing/accessory/petcollar/C = O
|
||||
if(user.drop_item())
|
||||
C.forceMove(src)
|
||||
collar = C
|
||||
collar.equipped(src)
|
||||
regenerate_icons()
|
||||
to_chat(usr, "<span class='notice'>You put \the [C] around \the [src]'s neck.</span>")
|
||||
if(C.tagname)
|
||||
name = C.tagname
|
||||
real_name = C.tagname
|
||||
return
|
||||
else
|
||||
return ..()
|
||||
|
||||
/mob/living/simple_animal/attack_hand(mob/living/carbon/human/M)
|
||||
..()
|
||||
switch(M.a_intent)
|
||||
|
||||
if(INTENT_HELP)
|
||||
if(health > 0)
|
||||
visible_message("<span class='notice'>[M] [response_help] [src].</span>")
|
||||
visible_message("<span class='notice'>[M] [response_help] [src].</span>", "<span class='notice'>[M] [response_help] you.</span>")
|
||||
playsound(loc, 'sound/weapons/thudswoosh.ogg', 50, 1, -1)
|
||||
|
||||
if(INTENT_GRAB)
|
||||
@@ -12,12 +28,12 @@
|
||||
|
||||
if(INTENT_HARM, INTENT_DISARM)
|
||||
M.do_attack_animation(src, ATTACK_EFFECT_PUNCH)
|
||||
visible_message("<span class='danger'>[M] [response_harm] [src]!</span>")
|
||||
visible_message("<span class='danger'>[M] [response_harm] [src]!</span>", "<span class='userdanger'>[M] [response_harm] you!</span>")
|
||||
playsound(loc, attacked_sound, 25, 1, -1)
|
||||
attack_threshold_check(harm_intent_damage)
|
||||
add_attack_logs(M, src, "Melee attacked with fists")
|
||||
updatehealth()
|
||||
return 1
|
||||
return TRUE
|
||||
|
||||
/mob/living/simple_animal/attack_hulk(mob/living/carbon/human/user, does_attack_animation = FALSE)
|
||||
if(user.a_intent == INTENT_HARM)
|
||||
@@ -39,10 +55,11 @@
|
||||
|
||||
/mob/living/simple_animal/attack_larva(mob/living/carbon/alien/larva/L)
|
||||
if(..()) //successful larva bite
|
||||
var/damage = rand(5, 10)
|
||||
if(stat != DEAD)
|
||||
L.amount_grown = min(L.amount_grown + damage, L.max_grown)
|
||||
attack_threshold_check(damage)
|
||||
var/damage = rand(5, 10)
|
||||
. = attack_threshold_check(damage)
|
||||
if(.)
|
||||
L.amount_grown = min(L.amount_grown + damage, L.max_grown)
|
||||
|
||||
/mob/living/simple_animal/attack_animal(mob/living/simple_animal/M)
|
||||
if(..())
|
||||
@@ -51,21 +68,57 @@
|
||||
|
||||
/mob/living/simple_animal/attack_slime(mob/living/carbon/slime/M)
|
||||
..()
|
||||
var/damage = rand(1, 3)
|
||||
|
||||
var/damage = rand(15, 25)
|
||||
if(M.is_adult)
|
||||
damage = rand(20, 40)
|
||||
else
|
||||
damage = rand(5, 35)
|
||||
|
||||
damage = rand(20, 35)
|
||||
attack_threshold_check(damage)
|
||||
return
|
||||
|
||||
/mob/living/simple_animal/proc/attack_threshold_check(damage, damagetype = BRUTE)
|
||||
if(damage <= force_threshold || !damage_coeff[damagetype])
|
||||
visible_message("<span class='warning'>[src] looks unharmed.</span>")
|
||||
/mob/living/simple_animal/proc/attack_threshold_check(damage, damagetype = BRUTE, armorcheck = "melee")
|
||||
var/temp_damage = damage
|
||||
if(!damage_coeff[damagetype])
|
||||
temp_damage = 0
|
||||
else
|
||||
apply_damage(damage, damagetype)
|
||||
temp_damage *= damage_coeff[damagetype]
|
||||
|
||||
if(temp_damage >= 0 && temp_damage <= force_threshold)
|
||||
visible_message("<span class='warning'>[src] looks unharmed.</span>")
|
||||
return FALSE
|
||||
else
|
||||
apply_damage(damage, damagetype, null, getarmor(null, armorcheck))
|
||||
return TRUE
|
||||
|
||||
/mob/living/simple_animal/bullet_act(obj/item/projectile/Proj)
|
||||
if(!Proj)
|
||||
return
|
||||
apply_damage(Proj.damage, Proj.damage_type)
|
||||
Proj.on_hit(src, 0)
|
||||
return FALSE
|
||||
|
||||
/mob/living/simple_animal/ex_act(severity, origin)
|
||||
if(origin && istype(origin, /datum/spacevine_mutation) && isvineimmune(src))
|
||||
return
|
||||
..()
|
||||
var/bomb_armor = getarmor(null, "bomb")
|
||||
switch(severity)
|
||||
if(1)
|
||||
if(prob(bomb_armor))
|
||||
adjustBruteLoss(500)
|
||||
else
|
||||
gib()
|
||||
return
|
||||
if(2)
|
||||
var/bloss = 60
|
||||
if(prob(bomb_armor))
|
||||
bloss = bloss / 1.5
|
||||
adjustBruteLoss(bloss)
|
||||
if(3)
|
||||
var/bloss = 30
|
||||
if(prob(bomb_armor))
|
||||
bloss = bloss / 1.5
|
||||
adjustBruteLoss(bloss)
|
||||
|
||||
/mob/living/simple_animal/blob_act(obj/structure/blob/B)
|
||||
adjustBruteLoss(20)
|
||||
|
||||
/mob/living/simple_animal/do_attack_animation(atom/A, visual_effect_icon, used_item, no_effect, end_pixel_y)
|
||||
if(!no_effect && !visual_effect_icon && melee_damage_upper)
|
||||
|
||||
@@ -241,10 +241,10 @@
|
||||
else
|
||||
to_chat(user, "[src] is in pristine condition.")
|
||||
|
||||
/mob/living/simple_animal/bot/adjustHealth(amount)
|
||||
/mob/living/simple_animal/bot/adjustHealth(amount, updating_health = TRUE)
|
||||
if(amount > 0 && prob(10))
|
||||
new /obj/effect/decal/cleanable/blood/oil(loc)
|
||||
return ..(amount)
|
||||
. = ..()
|
||||
|
||||
/mob/living/simple_animal/bot/updatehealth(reason = "none given")
|
||||
..(reason)
|
||||
|
||||
@@ -217,7 +217,7 @@
|
||||
|
||||
|
||||
/mob/living/simple_animal/hostile/construct/builder/Found(atom/A) //what have we found here?
|
||||
if(istype(A, /mob/living/simple_animal/hostile/construct)) //is it a construct?
|
||||
if(isconstruct(A)) //is it a construct?
|
||||
var/mob/living/simple_animal/hostile/construct/C = A
|
||||
if(C.health < C.maxHealth) //is it hurt? let's go heal it if it is
|
||||
return 1
|
||||
@@ -236,7 +236,7 @@
|
||||
..()
|
||||
if(isliving(target))
|
||||
var/mob/living/L = target
|
||||
if(istype(L, /mob/living/simple_animal/hostile/construct) && L.health >= L.maxHealth) //is this target an unhurt construct? stop trying to heal it
|
||||
if(isconstruct(L) && L.health >= L.maxHealth) //is this target an unhurt construct? stop trying to heal it
|
||||
LoseTarget()
|
||||
return 0
|
||||
if(L.health <= melee_damage_lower+melee_damage_upper) //ey bucko you're hurt as fuck let's go hit you
|
||||
@@ -245,7 +245,7 @@
|
||||
|
||||
/mob/living/simple_animal/hostile/construct/builder/Aggro()
|
||||
..()
|
||||
if(istype(target, /mob/living/simple_animal/hostile/construct)) //oh the target is a construct no need to flee
|
||||
if(isconstruct(target)) //oh the target is a construct no need to flee
|
||||
retreat_distance = null
|
||||
minimum_distance = 1
|
||||
|
||||
@@ -256,7 +256,7 @@
|
||||
|
||||
/mob/living/simple_animal/hostile/construct/builder/hostile //actually hostile, will move around, hit things, heal other constructs
|
||||
AIStatus = AI_ON
|
||||
environment_smash = 1 //only token destruction, don't smash the cult wall NO STOP
|
||||
environment_smash = ENVIRONMENT_SMASH_STRUCTURES //only token destruction, don't smash the cult wall NO STOP
|
||||
|
||||
|
||||
/////////////////////////////Behemoth/////////////////////////
|
||||
|
||||
@@ -0,0 +1,37 @@
|
||||
|
||||
/mob/living/simple_animal/proc/adjustHealth(amount, updating_health = TRUE)
|
||||
if(status_flags & GODMODE)
|
||||
return FALSE
|
||||
var/oldbruteloss = bruteloss
|
||||
bruteloss = Clamp(bruteloss + amount, 0, maxHealth)
|
||||
if(oldbruteloss == bruteloss)
|
||||
updating_health = FALSE
|
||||
. = STATUS_UPDATE_NONE
|
||||
else
|
||||
. = STATUS_UPDATE_HEALTH
|
||||
if(updating_health)
|
||||
updatehealth()
|
||||
|
||||
/mob/living/simple_animal/adjustBruteLoss(amount, updating_health = TRUE)
|
||||
if(damage_coeff[BRUTE])
|
||||
return adjustHealth(amount * damage_coeff[BRUTE], updating_health)
|
||||
|
||||
/mob/living/simple_animal/adjustFireLoss(amount, updating_health = TRUE)
|
||||
if(damage_coeff[BURN])
|
||||
return adjustHealth(amount * damage_coeff[BURN], updating_health)
|
||||
|
||||
/mob/living/simple_animal/adjustOxyLoss(amount, updating_health = TRUE)
|
||||
if(damage_coeff[OXY])
|
||||
return adjustHealth(amount * damage_coeff[OXY], updating_health)
|
||||
|
||||
/mob/living/simple_animal/adjustToxLoss(amount, updating_health = TRUE)
|
||||
if(damage_coeff[TOX])
|
||||
return adjustHealth(amount * damage_coeff[TOX], updating_health)
|
||||
|
||||
/mob/living/simple_animal/adjustCloneLoss(amount, updating_health = TRUE)
|
||||
if(damage_coeff[CLONE])
|
||||
return adjustHealth(amount * damage_coeff[CLONE], updating_health)
|
||||
|
||||
/mob/living/simple_animal/adjustStaminaLoss(amount, updating_health = TRUE)
|
||||
if(damage_coeff[STAMINA])
|
||||
return ..(amount*damage_coeff[STAMINA], updating_health)
|
||||
@@ -94,26 +94,27 @@
|
||||
new cat_type(loc)
|
||||
|
||||
|
||||
/mob/living/simple_animal/pet/cat/handle_automated_action()
|
||||
/mob/living/simple_animal/pet/cat/Life()
|
||||
..()
|
||||
if(prob(1))
|
||||
custom_emote(1, pick("stretches out for a belly rub.", "wags its tail.", "lies down."))
|
||||
icon_state = "[icon_living]_rest"
|
||||
resting = 1
|
||||
update_canmove()
|
||||
else if (prob(1))
|
||||
custom_emote(1, pick("sits down.", "crouches on its hind legs.", "looks alert."))
|
||||
icon_state = "[icon_living]_sit"
|
||||
resting = 1
|
||||
update_canmove()
|
||||
else if (prob(1))
|
||||
if (resting)
|
||||
custom_emote(1, pick("gets up and meows.", "walks around.", "stops resting."))
|
||||
icon_state = "[icon_living]"
|
||||
resting = 0
|
||||
make_babies()
|
||||
|
||||
|
||||
/mob/living/simple_animal/pet/cat/handle_automated_action()
|
||||
if(!stat && !buckled)
|
||||
if(prob(1))
|
||||
custom_emote(1, pick("stretches out for a belly rub.", "wags its tail.", "lies down."))
|
||||
StartResting()
|
||||
else if(prob(1))
|
||||
custom_emote(1, pick("sits down.", "crouches on its hind legs.", "looks alert."))
|
||||
icon_state = "[icon_living]_sit"
|
||||
resting = TRUE
|
||||
update_canmove()
|
||||
else
|
||||
custom_emote(1, pick("grooms its fur.", "twitches its whiskers.", "shakes out its coat."))
|
||||
else if(prob(1))
|
||||
if(resting)
|
||||
custom_emote(1, pick("gets up and meows.", "walks around.", "stops resting."))
|
||||
StopResting()
|
||||
else
|
||||
custom_emote(1, pick("grooms its fur.", "twitches its whiskers.", "shakes out its coat."))
|
||||
|
||||
//MICE!
|
||||
if(eats_mice && isturf(loc) && !incapacitated())
|
||||
@@ -128,10 +129,9 @@
|
||||
if(T.cooldown < (world.time - 400))
|
||||
custom_emote(1, "bats \the [T] around with its paw!")
|
||||
T.cooldown = world.time
|
||||
make_babies()
|
||||
|
||||
/mob/living/simple_animal/pet/cat/handle_automated_movement()
|
||||
..()
|
||||
. = ..()
|
||||
if(!stat && !resting && !buckled)
|
||||
turns_since_scan++
|
||||
if(turns_since_scan > 5)
|
||||
|
||||
@@ -451,9 +451,8 @@
|
||||
response_harm = "kicks"
|
||||
gold_core_spawnable = CHEM_MOB_SPAWN_INVALID
|
||||
|
||||
/mob/living/simple_animal/pet/corgi/Ian/Life()
|
||||
..()
|
||||
|
||||
/mob/living/simple_animal/pet/corgi/Ian/handle_automated_movement()
|
||||
. = ..()
|
||||
//Feeding, chasing food, FOOOOODDDD
|
||||
if(!resting && !buckled)
|
||||
turns_since_scan++
|
||||
@@ -580,9 +579,10 @@
|
||||
|
||||
/mob/living/simple_animal/pet/corgi/Lisa/Life()
|
||||
..()
|
||||
|
||||
make_babies()
|
||||
|
||||
/mob/living/simple_animal/pet/corgi/Lisa/handle_automated_movement()
|
||||
. = ..()
|
||||
if(!resting && !buckled)
|
||||
if(prob(1))
|
||||
custom_emote(1, pick("dances around.","chases her tail."))
|
||||
@@ -651,15 +651,16 @@
|
||||
|
||||
/mob/living/simple_animal/pet/corgi/Ian/borgi/Life(seconds, times_fired)
|
||||
..()
|
||||
if(emagged && prob(25))
|
||||
var/mob/living/carbon/target = locate() in view(10,src)
|
||||
if(target)
|
||||
shootAt(target)
|
||||
|
||||
//spark for no reason
|
||||
if(prob(5))
|
||||
do_sparks(3, 1, src)
|
||||
|
||||
/mob/living/simple_animal/pet/corgi/Ian/borgi/handle_automated_action()
|
||||
if(emagged && prob(25))
|
||||
var/mob/living/carbon/target = locate() in view(10, src)
|
||||
if(target)
|
||||
shootAt(target)
|
||||
|
||||
/mob/living/simple_animal/pet/corgi/Ian/borgi/death(gibbed)
|
||||
// Only execute the below if we successfully died
|
||||
. = ..(gibbed)
|
||||
|
||||
@@ -17,8 +17,6 @@
|
||||
stop_automated_movement = 1
|
||||
friendly = "pinches"
|
||||
ventcrawler = 2
|
||||
var/obj/item/inventory_head
|
||||
var/obj/item/inventory_mask
|
||||
can_hide = 1
|
||||
can_collar = 1
|
||||
gold_core_spawnable = CHEM_MOB_SPAWN_FRIENDLY
|
||||
@@ -32,11 +30,6 @@
|
||||
var/east_vs_west = pick(4, 8)
|
||||
if(Process_Spacemove(east_vs_west))
|
||||
Move(get_step(src, east_vs_west), east_vs_west)
|
||||
turns_since_move = 0
|
||||
|
||||
/mob/living/simple_animal/crab/Life(seconds, times_fired)
|
||||
. = ..()
|
||||
regenerate_icons()
|
||||
|
||||
//COFFEE! SQUEEEEEEEEE!
|
||||
/mob/living/simple_animal/crab/Coffee
|
||||
|
||||
@@ -34,12 +34,11 @@
|
||||
. = ..()
|
||||
|
||||
/mob/living/simple_animal/hostile/retaliate/goat/Destroy()
|
||||
qdel(udder)
|
||||
udder = null
|
||||
QDEL_NULL(udder)
|
||||
return ..()
|
||||
|
||||
/mob/living/simple_animal/hostile/retaliate/goat/handle_automated_movement()
|
||||
..()
|
||||
. = ..()
|
||||
//chance to go crazy and start wacking stuff
|
||||
if(!enemies.len && prob(1))
|
||||
Retaliate()
|
||||
@@ -49,14 +48,13 @@
|
||||
LoseTarget()
|
||||
visible_message("<span class='notice'>[src] calms down.</span>")
|
||||
|
||||
if(stat == CONSCIOUS)
|
||||
eat_plants()
|
||||
if(!pulledby)
|
||||
for(var/direction in shuffle(list(1,2,4,8,5,6,9,10)))
|
||||
var/step = get_step(src, direction)
|
||||
if(step)
|
||||
if(locate(/obj/structure/spacevine) in step || locate(/obj/structure/glowshroom) in step)
|
||||
Move(step, get_dir(src, step))
|
||||
eat_plants()
|
||||
if(!pulledby)
|
||||
for(var/direction in shuffle(list(1, 2, 4, 8, 5, 6, 9, 10)))
|
||||
var/step = get_step(src, direction)
|
||||
if(step)
|
||||
if(locate(/obj/structure/spacevine) in step || locate(/obj/structure/glowshroom) in step)
|
||||
Move(step, get_dir(src, step))
|
||||
|
||||
/mob/living/simple_animal/hostile/retaliate/goat/Life(seconds, times_fired)
|
||||
. = ..()
|
||||
@@ -94,8 +92,8 @@
|
||||
say("Nom")
|
||||
|
||||
/mob/living/simple_animal/hostile/retaliate/goat/AttackingTarget()
|
||||
..()
|
||||
if(isdiona(target))
|
||||
. = ..()
|
||||
if(. && isdiona(target))
|
||||
var/mob/living/carbon/human/H = target
|
||||
var/obj/item/organ/external/NB = pick(H.bodyparts)
|
||||
H.visible_message("<span class='warning'>[src] takes a big chomp out of [H]!</span>", "<span class='userdanger'>[src] takes a big chomp out of your [NB.name]!</span>")
|
||||
|
||||
@@ -56,28 +56,19 @@
|
||||
visible_message("<span class='warning'>[src] chews through [C].</span>")
|
||||
|
||||
/mob/living/simple_animal/mouse/handle_automated_speech()
|
||||
..()
|
||||
if(prob(speak_chance))
|
||||
for(var/mob/M in view())
|
||||
M << squeak_sound
|
||||
|
||||
/mob/living/simple_animal/mouse/Life(seconds, times_fired)
|
||||
. = ..()
|
||||
if(stat == UNCONSCIOUS)
|
||||
if(ckey || prob(1))
|
||||
stat = CONSCIOUS
|
||||
icon_state = "mouse_[mouse_color]"
|
||||
wander = 1
|
||||
else if(prob(5))
|
||||
emote("snuffles")
|
||||
|
||||
/mob/living/simple_animal/mouse/Life()
|
||||
..()
|
||||
if(prob(0.5) && !ckey)
|
||||
stat = UNCONSCIOUS
|
||||
icon_state = "mouse_[mouse_color]_sleep"
|
||||
wander = 0
|
||||
speak_chance = 0
|
||||
if(prob(speak_chance) && !incapacitated())
|
||||
playsound(src, squeak_sound, 100, 1)
|
||||
|
||||
/mob/living/simple_animal/mouse/handle_automated_movement()
|
||||
. = ..()
|
||||
if(resting)
|
||||
if(prob(1))
|
||||
StopResting()
|
||||
else if(prob(5))
|
||||
custom_emote(2, "snuffles")
|
||||
else if(prob(0.5))
|
||||
StartResting()
|
||||
|
||||
/mob/living/simple_animal/mouse/New()
|
||||
..()
|
||||
@@ -119,7 +110,7 @@
|
||||
desc = "It's toast."
|
||||
death()
|
||||
|
||||
/mob/living/simple_animal/mouse/death(gibbed)
|
||||
/mob/living/simple_animal/mouse/death(gibbed)
|
||||
// Only execute the below if we successfully died
|
||||
playsound(src, squeak_sound, 40, 1)
|
||||
. = ..(gibbed)
|
||||
|
||||
@@ -19,13 +19,12 @@
|
||||
see_in_dark = 5
|
||||
gold_core_spawnable = CHEM_MOB_SPAWN_FRIENDLY
|
||||
|
||||
/mob/living/simple_animal/pet/pug/Life()
|
||||
..()
|
||||
|
||||
/mob/living/simple_animal/pet/pug/handle_automated_movement()
|
||||
. = ..()
|
||||
if(!resting && !buckled)
|
||||
if(prob(1))
|
||||
custom_emote(1, pick("chases its tail."))
|
||||
spawn(0)
|
||||
for(var/i in list(1,2,4,8,4,2,1,2,4,8,4,2,1,2,4,8,4,2))
|
||||
for(var/i in list(1, 2, 4, 8, 4, 2, 1, 2, 4, 8, 4, 2, 1, 2, 4, 8, 4, 2))
|
||||
dir = i
|
||||
sleep(1)
|
||||
sleep(1)
|
||||
@@ -158,7 +158,8 @@
|
||||
if(istype(target, /obj/effect/decal/cleanable))
|
||||
visible_message("<span class='notice'>\The [src] cleans up \the [target].</span>")
|
||||
qdel(target)
|
||||
return
|
||||
return TRUE
|
||||
var/atom/movable/M = target
|
||||
M.clean_blood()
|
||||
visible_message("<span class='notice'>\The [src] polishes \the [target].</span>")
|
||||
return TRUE
|
||||
|
||||
@@ -22,6 +22,9 @@
|
||||
attacktext = "bites"
|
||||
attack_sound = 'sound/weapons/bite.ogg'
|
||||
|
||||
emote_taunt = list("flutters")
|
||||
taunt_chance = 20
|
||||
|
||||
atmos_requirements = list("min_oxy" = 0, "max_oxy" = 0, "min_tox" = 0, "max_tox" = 0, "min_co2" = 0, "max_co2" = 0, "min_n2" = 0, "max_n2" = 0)
|
||||
minbodytemp = 0
|
||||
|
||||
@@ -39,11 +42,6 @@
|
||||
/mob/living/simple_animal/hostile/scarybat/Process_Spacemove(var/check_drift = 0)
|
||||
return ..() //No drifting in space for space carp! //original comments do not steal
|
||||
|
||||
/mob/living/simple_animal/hostile/scarybat/FindTarget()
|
||||
. = ..()
|
||||
if(.)
|
||||
custom_emote(1, "flutters towards [.]")
|
||||
|
||||
/mob/living/simple_animal/hostile/scarybat/Found(var/atom/A)//This is here as a potential override to pick a specific target if available
|
||||
if(istype(A) && A == owner)
|
||||
return 0
|
||||
|
||||
@@ -137,12 +137,13 @@
|
||||
if(target == beehome)
|
||||
var/obj/structure/beebox/BB = target
|
||||
forceMove(BB)
|
||||
toggle_ai(AI_IDLE)
|
||||
target = null
|
||||
wanted_objects -= beehometypecache //so we don't attack beeboxes when not going home
|
||||
return //no don't attack the goddamm box
|
||||
else
|
||||
..()
|
||||
if(isliving(target) && (!client || a_intent == INTENT_HARM))
|
||||
. = ..()
|
||||
if(. && isliving(target) && (!client || a_intent == INTENT_HARM))
|
||||
var/mob/living/L = target
|
||||
if(L.reagents)
|
||||
if(beegent)
|
||||
@@ -222,8 +223,8 @@
|
||||
|
||||
//leave pollination for the peasent bees
|
||||
/mob/living/simple_animal/hostile/poison/bees/queen/AttackingTarget()
|
||||
..()
|
||||
if(beegent && isliving(target))
|
||||
. = ..()
|
||||
if(. && beegent && isliving(target))
|
||||
var/mob/living/L = target
|
||||
beegent.reaction_mob(L, TOUCH)
|
||||
L.reagents.add_reagent(beegent.id, rand(1, 5))
|
||||
@@ -283,6 +284,14 @@
|
||||
QDEL_NULL(queen)
|
||||
return ..()
|
||||
|
||||
/mob/living/simple_animal/hostile/poison/bees/consider_wakeup()
|
||||
if(beehome && loc == beehome) // If bees are chilling in their nest, they're not actively looking for targets
|
||||
idle = min(100, ++idle)
|
||||
if(idle >= BEE_IDLE_ROAMING && prob(BEE_PROB_GOROAM))
|
||||
toggle_ai(AI_ON)
|
||||
forceMove(beehome.drop_location())
|
||||
else
|
||||
..()
|
||||
|
||||
//Syndicate Bees
|
||||
/mob/living/simple_animal/hostile/poison/bees/syndi
|
||||
@@ -327,8 +336,8 @@
|
||||
return TRUE
|
||||
|
||||
/mob/living/simple_animal/hostile/poison/bees/syndi/AttackingTarget()
|
||||
..()
|
||||
if(target && isliving(target))
|
||||
. = ..()
|
||||
if(. && target && isliving(target))
|
||||
var/mob/living/L = target
|
||||
if(L.stat)
|
||||
LoseTarget()
|
||||
@@ -10,6 +10,8 @@
|
||||
response_help = "pets the"
|
||||
response_disarm = "gently pushes aside the"
|
||||
response_harm = "hits the"
|
||||
emote_taunt = list("gnashes")
|
||||
taunt_chance = 30
|
||||
speed = 0
|
||||
maxHealth = 25
|
||||
health = 25
|
||||
@@ -50,14 +52,9 @@
|
||||
/mob/living/simple_animal/hostile/carp/Process_Spacemove(var/movement_dir = 0)
|
||||
return 1 //No drifting in space for space carp! //original comments do not steal
|
||||
|
||||
/mob/living/simple_animal/hostile/carp/FindTarget()
|
||||
. = ..()
|
||||
if(.)
|
||||
custom_emote(1, "gnashes at [.]!")
|
||||
|
||||
/mob/living/simple_animal/hostile/carp/AttackingTarget()
|
||||
..()
|
||||
if(ishuman(target))
|
||||
. = ..()
|
||||
if(. && ishuman(target))
|
||||
var/mob/living/carbon/human/H = target
|
||||
H.adjustStaminaLoss(8)
|
||||
|
||||
|
||||
@@ -19,6 +19,8 @@
|
||||
attacktext = "grips"
|
||||
attack_sound = 'sound/hallucinations/growl1.ogg'
|
||||
speak_emote = list("growls")
|
||||
emote_taunt = list("wails")
|
||||
taunt_chance = 25
|
||||
|
||||
atmos_requirements = list("min_oxy" = 0, "max_oxy" = 0, "min_tox" = 0, "max_tox" = 0, "min_co2" = 0, "max_co2" = 0, "min_n2" = 0, "max_n2" = 0)
|
||||
minbodytemp = 0
|
||||
@@ -29,14 +31,9 @@
|
||||
/mob/living/simple_animal/hostile/faithless/Process_Spacemove(var/movement_dir = 0)
|
||||
return 1
|
||||
|
||||
/mob/living/simple_animal/hostile/faithless/FindTarget()
|
||||
. = ..()
|
||||
if(.)
|
||||
custom_emote(1, "wails at [.]!")
|
||||
|
||||
/mob/living/simple_animal/hostile/faithless/AttackingTarget()
|
||||
..()
|
||||
if(iscarbon(target))
|
||||
. = ..()
|
||||
if(. && iscarbon(target))
|
||||
var/mob/living/carbon/C = target
|
||||
if(prob(12))
|
||||
C.Weaken(3)
|
||||
|
||||
@@ -40,8 +40,8 @@
|
||||
|
||||
/mob/living/simple_animal/hostile/poison/giant_spider/AttackingTarget()
|
||||
// This is placed here, NOT on /poison, because the other subtypes of /poison/ already override AttackingTarget() completely, and as such it would do nothing but confuse people there.
|
||||
..()
|
||||
if(venom_per_bite > 0 && iscarbon(target) && (!client || a_intent == INTENT_HARM))
|
||||
. = ..()
|
||||
if(. && venom_per_bite > 0 && iscarbon(target) && (!client || a_intent == INTENT_HARM))
|
||||
var/mob/living/carbon/C = target
|
||||
var/inject_target = pick("chest", "head")
|
||||
if(C.can_inject(null, 0, inject_target, 0))
|
||||
@@ -76,20 +76,19 @@
|
||||
venom_per_bite = 10
|
||||
move_to_delay = 5
|
||||
|
||||
/mob/living/simple_animal/hostile/poison/giant_spider/hunter/handle_automated_action()
|
||||
if(!..()) //AIStatus is off
|
||||
return
|
||||
/mob/living/simple_animal/hostile/poison/giant_spider/handle_automated_movement() //Hacky and ugly.
|
||||
. = ..()
|
||||
if(AIStatus == AI_IDLE)
|
||||
//1% chance to skitter madly away
|
||||
if(!busy && prob(1))
|
||||
stop_automated_movement = 1
|
||||
Goto(pick(orange(20, src)), move_to_delay)
|
||||
Goto(pick(urange(20, src, 1)), move_to_delay)
|
||||
spawn(50)
|
||||
stop_automated_movement = 0
|
||||
walk(src,0)
|
||||
return 1
|
||||
|
||||
/mob/living/simple_animal/hostile/poison/giant_spider/nurse/proc/GiveUp(var/C)
|
||||
/mob/living/simple_animal/hostile/poison/giant_spider/nurse/proc/GiveUp(C)
|
||||
spawn(100)
|
||||
if(busy == MOVING_TO_TARGET)
|
||||
if(cocoon_target == C && get_dist(src,cocoon_target) > 1)
|
||||
@@ -97,13 +96,13 @@
|
||||
busy = 0
|
||||
stop_automated_movement = 0
|
||||
|
||||
/mob/living/simple_animal/hostile/poison/giant_spider/nurse/handle_automated_action()
|
||||
/mob/living/simple_animal/hostile/poison/giant_spider/nurse/handle_automated_movement() //Hacky and ugly.
|
||||
if(..())
|
||||
var/list/can_see = view(src, 10)
|
||||
if(!busy && prob(30)) //30% chance to stop wandering and do something
|
||||
//first, check for potential food nearby to cocoon
|
||||
//first, check for potential food nearby to cocoon
|
||||
for(var/mob/living/C in can_see)
|
||||
if(C.stat && !istype(C,/mob/living/simple_animal/hostile/poison/giant_spider))
|
||||
if(C.stat && !istype(C, /mob/living/simple_animal/hostile/poison/giant_spider) && !C.anchored)
|
||||
cocoon_target = C
|
||||
busy = MOVING_TO_TARGET
|
||||
Goto(C, move_to_delay)
|
||||
@@ -123,13 +122,14 @@
|
||||
for(var/obj/O in can_see)
|
||||
if(O.anchored)
|
||||
continue
|
||||
if(istype(O, /obj/item) || istype(O, /obj/structure) || istype(O, /obj/machinery))
|
||||
cocoon_target = O
|
||||
busy = MOVING_TO_TARGET
|
||||
stop_automated_movement = 1
|
||||
Goto(O, move_to_delay)
|
||||
//give up if we can't reach them after 10 seconds
|
||||
GiveUp(O)
|
||||
|
||||
if(isitem(O) || isstructure(O) || ismachinery(O))
|
||||
cocoon_target = O
|
||||
busy = MOVING_TO_TARGET
|
||||
stop_automated_movement = 1
|
||||
Goto(O, move_to_delay)
|
||||
//give up if we can't reach them after 10 seconds
|
||||
GiveUp(O)
|
||||
|
||||
else if(busy == MOVING_TO_TARGET && cocoon_target)
|
||||
if(get_dist(src, cocoon_target) <= 1)
|
||||
|
||||
@@ -36,11 +36,11 @@
|
||||
for(var/mob/living/L in T)
|
||||
if(L == src || L == A)
|
||||
continue
|
||||
if(faction_check(L) && !attack_same)
|
||||
if(faction_check_mob(L) && !attack_same)
|
||||
return
|
||||
visible_message("<span class='danger'><b>[src]</b> [ranged_message] at [A]!</span>")
|
||||
throw_at(A, jumpdistance, jumpspeed, spin = FALSE, diagonals_first = TRUE)
|
||||
ranged_cooldown = world.time + ranged_cooldown_time
|
||||
ranged_cooldown = world.time + ranged_cooldown_time
|
||||
|
||||
/mob/living/simple_animal/hostile/headcrab/proc/Zombify(mob/living/carbon/human/H)
|
||||
if(!H.check_death_method())
|
||||
|
||||
@@ -36,16 +36,14 @@
|
||||
else if(mind) // Let's make this a feature
|
||||
egg.origin = mind
|
||||
for(var/obj/item/organ/internal/I in src)
|
||||
I.loc = egg
|
||||
I.forceMove(egg)
|
||||
visible_message("<span class='warning'>[src] plants something in [victim]'s flesh!</span>", \
|
||||
"<span class='danger'>We inject our egg into [victim]'s body!</span>")
|
||||
egg_lain = 1
|
||||
|
||||
/mob/living/simple_animal/hostile/headslug/AttackingTarget()
|
||||
if(egg_lain)
|
||||
target.attack_animal(src)
|
||||
return
|
||||
if(iscarbon(target) && !issmall(target))
|
||||
. = ..()
|
||||
if(. && !egg_lain && iscarbon(target) && !issmall(target))
|
||||
// Changeling egg can survive in aliens!
|
||||
var/mob/living/carbon/C = target
|
||||
if(C.stat == DEAD)
|
||||
@@ -54,10 +52,7 @@
|
||||
return
|
||||
Infect(target)
|
||||
to_chat(src, "<span class='userdanger'>With our egg laid, our death approaches rapidly...</span>")
|
||||
spawn(100)
|
||||
death()
|
||||
return
|
||||
target.attack_animal(src)
|
||||
addtimer(CALLBACK(src, .proc/death), 100)
|
||||
|
||||
/obj/item/organ/internal/body_egg/changeling_egg
|
||||
name = "changeling egg"
|
||||
|
||||
@@ -42,19 +42,16 @@
|
||||
whisper_action.Grant(src)
|
||||
|
||||
/mob/living/simple_animal/hostile/hellhound/handle_automated_action()
|
||||
. = ..()
|
||||
if(!..())
|
||||
return
|
||||
if(resting)
|
||||
if(!wants_to_rest())
|
||||
custom_emote(1, "growls, and gets up.")
|
||||
playsound(get_turf(src), 'sound/hallucinations/growl2.ogg', 50, 1)
|
||||
icon_state = "[icon_living]"
|
||||
resting = 0
|
||||
update_canmove()
|
||||
StopResting()
|
||||
else if(wants_to_rest())
|
||||
custom_emote(1, "lays down, and starts to lick their wounds.")
|
||||
icon_state = "[icon_resting]"
|
||||
resting = 1
|
||||
update_canmove()
|
||||
StartResting()
|
||||
|
||||
/mob/living/simple_animal/hostile/hellhound/examine(mob/user)
|
||||
. = ..()
|
||||
@@ -97,7 +94,7 @@
|
||||
|
||||
/mob/living/simple_animal/hostile/hellhound/AttackingTarget()
|
||||
. = ..()
|
||||
if(ishuman(target) && (!client || a_intent == INTENT_HARM))
|
||||
if(. && ishuman(target) && (!client || a_intent == INTENT_HARM))
|
||||
special_aoe()
|
||||
|
||||
/mob/living/simple_animal/hostile/hellhound/attackby(obj/item/C, mob/user, params)
|
||||
|
||||
@@ -36,7 +36,7 @@
|
||||
|
||||
/mob/living/simple_animal/hostile/hivebot/rapid
|
||||
ranged = 1
|
||||
rapid = 1
|
||||
rapid = 3
|
||||
retreat_distance = 5
|
||||
minimum_distance = 5
|
||||
|
||||
|
||||
@@ -2,60 +2,60 @@
|
||||
faction = list("hostile")
|
||||
stop_automated_movement_when_pulled = 0
|
||||
obj_damage = 40
|
||||
environment_smash = 1 //Set to 1 to break closets,tables,racks, etc; 2 for walls; 3 for rwalls
|
||||
environment_smash = ENVIRONMENT_SMASH_STRUCTURES //Bitflags. Set to ENVIRONMENT_SMASH_STRUCTURES to break closets,tables,racks, etc; ENVIRONMENT_SMASH_WALLS for walls; ENVIRONMENT_SMASH_RWALLS for rwalls
|
||||
var/atom/target
|
||||
var/ranged = 0
|
||||
var/rapid = 0
|
||||
var/projectiletype
|
||||
var/ranged = FALSE
|
||||
var/rapid = 0 //How many shots per volley.
|
||||
var/rapid_fire_delay = 2 //Time between rapid fire shots
|
||||
|
||||
var/dodging = FALSE
|
||||
var/approaching_target = FALSE //We should dodge now
|
||||
var/in_melee = FALSE //We should sidestep now
|
||||
var/dodge_prob = 30
|
||||
var/sidestep_per_cycle = 1 //How many sidesteps per npcpool cycle when in melee
|
||||
|
||||
var/projectiletype //set ONLY it and NULLIFY casingtype var, if we have ONLY projectile
|
||||
var/projectilesound
|
||||
var/casingtype
|
||||
var/casingtype //set ONLY it and NULLIFY projectiletype, if we have projectile IN CASING
|
||||
var/move_to_delay = 3 //delay for the automated movement.
|
||||
var/list/friends = list()
|
||||
var/list/emote_taunt = list()
|
||||
var/taunt_chance = 0
|
||||
|
||||
var/rapid_melee = 1 //Number of melee attacks between each npc pool tick. Spread evenly.
|
||||
var/melee_queue_distance = 4 //If target is close enough start preparing to hit them if we have rapid_melee enabled
|
||||
|
||||
var/ranged_message = "fires" //Fluff text for ranged mobs
|
||||
var/ranged_cooldown = 0 //What the starting cooldown is on ranged attacks
|
||||
var/ranged_cooldown = 0 //What the current cooldown on ranged attacks is, generally world.time + ranged_cooldown_time
|
||||
var/ranged_cooldown_time = 30 //How long, in deciseconds, the cooldown of ranged attacks is
|
||||
var/ranged_ignores_vision = FALSE //if it'll fire ranged attacks even if it lacks vision on its target, only works with environment smash
|
||||
var/check_friendly_fire = 0 // Should the ranged mob check for friendlies when shooting
|
||||
var/retreat_distance = null //If our mob runs from players when they're too close, set in tile distance. By default, mobs do not retreat.
|
||||
var/minimum_distance = 1 //Minimum approach distance, so ranged mobs chase targets down, but still keep their distance set in tiles to the target, set higher to make mobs keep distance
|
||||
|
||||
|
||||
//These vars are related to how mobs locate and target
|
||||
var/robust_searching = 0 //By default, mobs have a simple searching method, set this to 1 for the more scrutinous searching (stat_attack, stat_exclusive, etc), should be disabled on most mobs
|
||||
var/vision_range = 9 //How big of an area to search for targets in, a vision of 9 attempts to find targets as soon as they walk into screen view
|
||||
var/aggro_vision_range = 9 //If a mob is aggro, we search in this radius. Defaults to 9 to keep in line with original simple mob aggro radius
|
||||
var/idle_vision_range = 9 //If a mob is just idling around, it's vision range is limited to this. Defaults to 9 to keep in line with original simple mob aggro radius
|
||||
var/search_objects = 0 //If we want to consider objects when searching around, set this to 1. If you want to search for objects while also ignoring mobs until hurt, set it to 2. To completely ignore mobs, even when attacked, set it to 3
|
||||
var/list/wanted_objects = list() //A list of objects that will be checked against to attack, should we have search_objects enabled
|
||||
var/stat_attack = 0 //Mobs with stat_attack to 1 will attempt to attack things that are unconscious, Mobs with stat_attack set to 2 will attempt to attack the dead.
|
||||
var/stat_exclusive = 0 //Mobs with this set to 1 will exclusively attack things defined by stat_attack, stat_attack 2 means they will only attack corpses
|
||||
var/attack_same = 0 //Set us to 1 to allow us to attack our own faction, or 2, to only ever attack our own faction
|
||||
|
||||
//typecache of things this mob will attack in DestroySurroundings() if it has environment_smash
|
||||
var/list/environment_target_typecache = list(
|
||||
/obj/machinery/door/window,
|
||||
/obj/structure/window,
|
||||
/obj/structure/closet,
|
||||
/obj/structure/table,
|
||||
/obj/structure/grille,
|
||||
/obj/structure/girder,
|
||||
/obj/structure/rack,
|
||||
/obj/structure/computerframe,
|
||||
/obj/machinery/constructable_frame,
|
||||
/obj/structure/barricade) //turned into a typecache in New()
|
||||
var/search_objects_timer_id //Timer for regaining our old search_objects value after being attacked
|
||||
var/search_objects_regain_time = 30 //the delay between being attacked and gaining our old search_objects value back
|
||||
var/list/wanted_objects = list() //A typecache of objects types that will be checked against to attack, should we have search_objects enabled
|
||||
var/stat_attack = CONSCIOUS //Mobs with stat_attack to UNCONSCIOUS will attempt to attack things that are unconscious, Mobs with stat_attack set to DEAD will attempt to attack the dead.
|
||||
var/stat_exclusive = FALSE //Mobs with this set to TRUE will exclusively attack things defined by stat_attack, stat_attack DEAD means they will only attack corpses
|
||||
var/attack_same = 0 //Set us to 1 to allow us to attack our own faction
|
||||
var/atom/targets_from = null //all range/attack/etc. calculations should be done from this atom, defaults to the mob itself, useful for Vehicles and such
|
||||
var/list/emote_taunt = list()
|
||||
var/taunt_chance = 0
|
||||
var/attack_all_objects = FALSE //if true, equivalent to having a wanted_objects list containing ALL objects.
|
||||
|
||||
var/lose_patience_timer_id //id for a timer to call LoseTarget(), used to stop mobs fixating on a target they can't reach
|
||||
var/lose_patience_timeout = 300 //30 seconds by default, so there's no major changes to AI behaviour, beyond actually bailing if stuck forever
|
||||
|
||||
var/attack_all_objects = FALSE //if true, equivalent to having a wanted_objects list containing ALL objects.
|
||||
/mob/living/simple_animal/hostile/Initialize(mapload)
|
||||
. = ..()
|
||||
|
||||
/mob/living/simple_animal/hostile/New()
|
||||
..()
|
||||
if(!targets_from)
|
||||
targets_from = src
|
||||
environment_target_typecache = typecacheof(environment_target_typecache)
|
||||
wanted_objects = typecacheof(wanted_objects)
|
||||
|
||||
/mob/living/simple_animal/hostile/Destroy()
|
||||
@@ -73,16 +73,46 @@
|
||||
if(AIStatus == AI_OFF)
|
||||
return 0
|
||||
var/list/possible_targets = ListTargets() //we look around for potential targets and make it a list for later use.
|
||||
|
||||
if(environment_smash)
|
||||
EscapeConfinement()
|
||||
|
||||
if(AICanContinue(possible_targets))
|
||||
DestroySurroundings()
|
||||
if(!QDELETED(target) && !targets_from.Adjacent(target))
|
||||
DestroyPathToTarget()
|
||||
if(!MoveToTarget(possible_targets)) //if we lose our target
|
||||
if(AIShouldSleep(possible_targets)) // we try to acquire a new one
|
||||
toggle_ai(AI_IDLE) // otherwise we go idle
|
||||
return 1
|
||||
|
||||
/mob/living/simple_animal/hostile/handle_automated_movement()
|
||||
. = ..()
|
||||
if(dodging && target && in_melee && isturf(loc) && isturf(target.loc))
|
||||
var/datum/cb = CALLBACK(src,.proc/sidestep)
|
||||
if(sidestep_per_cycle > 1) //For more than one just spread them equally - this could changed to some sensible distribution later
|
||||
var/sidestep_delay = SSnpcpool.wait / sidestep_per_cycle
|
||||
for(var/i in 1 to sidestep_per_cycle)
|
||||
addtimer(cb, (i - 1) * sidestep_delay)
|
||||
else //Otherwise randomize it to make the players guessing.
|
||||
addtimer(cb,rand(1, SSnpcpool.wait))
|
||||
|
||||
/mob/living/simple_animal/hostile/proc/sidestep()
|
||||
if(!target || !isturf(target.loc) || !isturf(loc) || stat == DEAD)
|
||||
return
|
||||
var/target_dir = get_dir(src, target)
|
||||
|
||||
var/static/list/cardinal_sidestep_directions = list(-90, -45, 0, 45, 90)
|
||||
var/static/list/diagonal_sidestep_directions = list(-45, 0, 45)
|
||||
var/chosen_dir = 0
|
||||
if (target_dir & (target_dir - 1))
|
||||
chosen_dir = pick(diagonal_sidestep_directions)
|
||||
else
|
||||
chosen_dir = pick(cardinal_sidestep_directions)
|
||||
if(chosen_dir)
|
||||
chosen_dir = turn(target_dir, chosen_dir)
|
||||
Move(get_step(src, chosen_dir))
|
||||
face_atom(target) //Looks better if they keep looking at you when dodging
|
||||
|
||||
/mob/living/simple_animal/hostile/attacked_by(obj/item/I, mob/living/user)
|
||||
if(stat == CONSCIOUS && !target && AIStatus != AI_OFF && !client && user)
|
||||
FindTarget(list(user), 1)
|
||||
@@ -97,7 +127,6 @@
|
||||
|
||||
//////////////HOSTILE MOB TARGETTING AND AGGRESSION////////////
|
||||
|
||||
|
||||
/mob/living/simple_animal/hostile/proc/ListTargets()//Step 1, find out what we can see
|
||||
if(!search_objects)
|
||||
. = hearers(vision_range, targets_from) - src //Remove self, so we don't suicide
|
||||
@@ -108,7 +137,11 @@
|
||||
if(can_see(targets_from, HM, vision_range))
|
||||
. += HM
|
||||
else
|
||||
. = oview(vision_range, targets_from)
|
||||
. = list() // The following code is only very slightly slower than just returning oview(vision_range, targets_from), but it saves us much more work down the line, particularly when bees are involved
|
||||
for(var/obj/A in oview(vision_range, targets_from))
|
||||
. += A
|
||||
for(var/mob/A in oview(vision_range, targets_from))
|
||||
. += A
|
||||
|
||||
/mob/living/simple_animal/hostile/proc/FindTarget(var/list/possible_targets, var/HasTargetsList = 0)//Step 2, filter down possible targets to things we actually care about
|
||||
. = list()
|
||||
@@ -153,59 +186,61 @@
|
||||
var/chosen_target = pick(Targets)//Pick the remaining targets (if any) at random
|
||||
return chosen_target
|
||||
|
||||
/mob/living/simple_animal/hostile/CanAttack(var/atom/the_target)//Can we actually attack a possible target?
|
||||
if(!the_target)
|
||||
return 0
|
||||
if(see_invisible < the_target.invisibility)//Target's invisible to us, forget it
|
||||
return 0
|
||||
// Please do not add one-off mob AIs here, but override this function for your mob
|
||||
/mob/living/simple_animal/hostile/CanAttack(atom/the_target)//Can we actually attack a possible target?
|
||||
if(isturf(the_target) || !the_target || the_target.type == /atom/movable/lighting_object) // bail out on invalids
|
||||
return FALSE
|
||||
|
||||
if(ismob(the_target)) //Target is in godmode, ignore it.
|
||||
var/mob/M = the_target
|
||||
if(M.status_flags & GODMODE)
|
||||
return FALSE
|
||||
|
||||
if(see_invisible < the_target.invisibility) //Target's invisible to us, forget it
|
||||
return FALSE
|
||||
if(search_objects < 2)
|
||||
if(isliving(the_target))
|
||||
var/mob/living/L = the_target
|
||||
var/faction_check = faction_check(L)
|
||||
var/faction_check = faction_check_mob(L)
|
||||
if(robust_searching)
|
||||
if(L.stat > stat_attack || L.stat != stat_attack && stat_exclusive == 1)
|
||||
return 0
|
||||
if(faction_check && !attack_same || !faction_check && attack_same == 2)
|
||||
return 0
|
||||
if(L in friends)
|
||||
return 0
|
||||
else
|
||||
if(L.stat)
|
||||
return 0
|
||||
if(faction_check && !attack_same)
|
||||
return 0
|
||||
return 1
|
||||
return FALSE
|
||||
if(L.stat > stat_attack)
|
||||
return FALSE
|
||||
if(L in friends)
|
||||
return FALSE
|
||||
else
|
||||
if((faction_check && !attack_same) || L.stat)
|
||||
return FALSE
|
||||
return TRUE
|
||||
|
||||
if(ishuman(the_target))
|
||||
var/mob/living/carbon/human/H = the_target
|
||||
if(is_type_in_list(src, H.dna.species.ignored_by))
|
||||
return 0
|
||||
|
||||
if(istype(the_target, /obj/mecha))
|
||||
if(ismecha(the_target))
|
||||
var/obj/mecha/M = the_target
|
||||
if(M.occupant)//Just so we don't attack empty mechs
|
||||
if(CanAttack(M.occupant))
|
||||
return 1
|
||||
return TRUE
|
||||
|
||||
if(istype(the_target, /obj/spacepod))
|
||||
if(isspacepod(the_target))
|
||||
var/obj/spacepod/S = the_target
|
||||
if(S.pilot) //Just so we don't attack empty pods
|
||||
if(S.pilot)//Just so we don't attack empty pods
|
||||
if(CanAttack(S.pilot))
|
||||
return 1
|
||||
return TRUE
|
||||
|
||||
if(istype(the_target, /obj/machinery/porta_turret))
|
||||
var/obj/machinery/porta_turret/P = the_target
|
||||
if(P.faction in faction)
|
||||
return 0
|
||||
return FALSE
|
||||
if(!P.raised) //Don't attack invincible turrets
|
||||
return 0
|
||||
return FALSE
|
||||
if(P.stat & BROKEN) //Or turrets that are already broken
|
||||
return 0
|
||||
return 1
|
||||
return FALSE
|
||||
return TRUE
|
||||
|
||||
if(isobj(the_target))
|
||||
if(attack_all_objects || is_type_in_list(the_target, wanted_objects))
|
||||
return 1
|
||||
return 0
|
||||
if(attack_all_objects || is_type_in_typecache(the_target, wanted_objects))
|
||||
return TRUE
|
||||
|
||||
return FALSE
|
||||
|
||||
/mob/living/simple_animal/hostile/proc/GiveTarget(new_target)//Step 4, give us our selected target
|
||||
target = new_target
|
||||
@@ -215,19 +250,39 @@
|
||||
Aggro()
|
||||
return 1
|
||||
|
||||
/mob/living/simple_animal/hostile/proc/MoveToTarget(var/list/possible_targets)//Step 5, handle movement between us and our target
|
||||
//What we do after closing in
|
||||
/mob/living/simple_animal/hostile/proc/MeleeAction(patience = TRUE)
|
||||
if(rapid_melee > 1)
|
||||
var/datum/callback/cb = CALLBACK(src, .proc/CheckAndAttack)
|
||||
var/delay = SSnpcpool.wait / rapid_melee
|
||||
for(var/i in 1 to rapid_melee)
|
||||
addtimer(cb, (i - 1)*delay)
|
||||
else
|
||||
AttackingTarget()
|
||||
if(patience)
|
||||
GainPatience()
|
||||
|
||||
/mob/living/simple_animal/hostile/proc/CheckAndAttack()
|
||||
if(target && targets_from && isturf(targets_from.loc) && target.Adjacent(targets_from) && !incapacitated())
|
||||
AttackingTarget()
|
||||
|
||||
/mob/living/simple_animal/hostile/proc/MoveToTarget(list/possible_targets)//Step 5, handle movement between us and our target
|
||||
stop_automated_movement = 1
|
||||
if(!target || !CanAttack(target))
|
||||
LoseTarget()
|
||||
return 0
|
||||
if(target in possible_targets)
|
||||
if(target.z != z)
|
||||
var/turf/T = get_turf(src)
|
||||
if(target.z != T.z)
|
||||
LoseTarget()
|
||||
return 0
|
||||
var/target_distance = get_dist(targets_from,target)
|
||||
if(ranged) //We ranged? Shoot at em
|
||||
if(!target.Adjacent(targets_from) && ranged_cooldown <= world.time) //But make sure they're not in range for a melee attack and our range attack is off cooldown
|
||||
OpenFire(target)
|
||||
if(!Process_Spacemove()) //Drifting
|
||||
walk(src,0)
|
||||
return 1
|
||||
if(retreat_distance != null) //If we have a retreat distance, check if we need to run from our target
|
||||
if(target_distance <= retreat_distance) //If target's closer than our retreat distance, run
|
||||
walk_away(src,target,retreat_distance,move_to_delay)
|
||||
@@ -237,8 +292,11 @@
|
||||
Goto(target,move_to_delay,minimum_distance)
|
||||
if(target)
|
||||
if(targets_from && isturf(targets_from.loc) && target.Adjacent(targets_from)) //If they're next to us, attack
|
||||
AttackingTarget()
|
||||
GainPatience()
|
||||
MeleeAction()
|
||||
else
|
||||
if(rapid_melee > 1 && target_distance <= melee_queue_distance)
|
||||
MeleeAction(FALSE)
|
||||
in_melee = FALSE //If we're just preparing to strike do not enter sidestep mode
|
||||
return 1
|
||||
return 0
|
||||
if(environment_smash)
|
||||
@@ -256,14 +314,18 @@
|
||||
return 0
|
||||
|
||||
/mob/living/simple_animal/hostile/proc/Goto(target, delay, minimum_distance)
|
||||
if(target == src.target)
|
||||
approaching_target = TRUE
|
||||
else
|
||||
approaching_target = FALSE
|
||||
walk_to(src, target, minimum_distance, delay)
|
||||
|
||||
/mob/living/simple_animal/hostile/adjustHealth(damage)
|
||||
/mob/living/simple_animal/hostile/adjustHealth(damage, updating_health = TRUE)
|
||||
. = ..()
|
||||
if(!ckey && !stat && search_objects < 3 && damage > 0)//Not unconscious, and we don't ignore mobs
|
||||
if(search_objects)//Turn off item searching and ignore whatever item we were looking at, we're more concerned with fight or flight
|
||||
search_objects = 0
|
||||
target = null
|
||||
LoseSearchObjects()
|
||||
if(AIStatus != AI_ON && AIStatus != AI_OFF)
|
||||
toggle_ai(AI_ON)
|
||||
FindTarget()
|
||||
@@ -271,7 +333,9 @@
|
||||
FindTarget()
|
||||
|
||||
/mob/living/simple_animal/hostile/proc/AttackingTarget()
|
||||
target.attack_animal(src)
|
||||
SEND_SIGNAL(src, COMSIG_HOSTILE_ATTACKINGTARGET, target)
|
||||
in_melee = TRUE
|
||||
return target.attack_animal(src)
|
||||
|
||||
/mob/living/simple_animal/hostile/proc/Aggro()
|
||||
vision_range = aggro_vision_range
|
||||
@@ -281,11 +345,13 @@
|
||||
|
||||
/mob/living/simple_animal/hostile/proc/LoseAggro()
|
||||
stop_automated_movement = 0
|
||||
vision_range = idle_vision_range
|
||||
vision_range = initial(vision_range)
|
||||
taunt_chance = initial(taunt_chance)
|
||||
|
||||
/mob/living/simple_animal/hostile/proc/LoseTarget()
|
||||
target = null
|
||||
approaching_target = FALSE
|
||||
in_melee = FALSE
|
||||
walk(src, 0)
|
||||
LoseAggro()
|
||||
|
||||
@@ -302,8 +368,7 @@
|
||||
do_alert_animation(src)
|
||||
playsound(loc, 'sound/machines/chime.ogg', 50, 1, -1)
|
||||
for(var/mob/living/simple_animal/hostile/M in oview(distance, targets_from))
|
||||
var/list/L = M.faction&faction
|
||||
if(L.len)
|
||||
if(faction_check_mob(M, TRUE))
|
||||
if(M.AIStatus == AI_OFF)
|
||||
return
|
||||
else
|
||||
@@ -323,21 +388,18 @@
|
||||
return
|
||||
visible_message("<span class='danger'><b>[src]</b> [ranged_message] at [A]!</span>")
|
||||
|
||||
if(rapid)
|
||||
spawn(1)
|
||||
Shoot(A)
|
||||
spawn(4)
|
||||
Shoot(A)
|
||||
spawn(6)
|
||||
Shoot(A)
|
||||
|
||||
if(rapid > 1)
|
||||
var/datum/callback/cb = CALLBACK(src, .proc/Shoot, A)
|
||||
for(var/i in 1 to rapid)
|
||||
addtimer(cb, (i - 1)*rapid_fire_delay)
|
||||
else
|
||||
Shoot(A)
|
||||
ranged_cooldown = world.time + ranged_cooldown_time
|
||||
|
||||
/mob/living/simple_animal/hostile/proc/Shoot(atom/targeted_atom)
|
||||
if(targeted_atom == targets_from.loc || targeted_atom == targets_from)
|
||||
if( QDELETED(targeted_atom) || targeted_atom == targets_from.loc || targeted_atom == targets_from )
|
||||
return
|
||||
|
||||
var/turf/startloc = get_turf(targets_from)
|
||||
if(casingtype)
|
||||
var/obj/item/ammo_casing/casing = new casingtype(startloc)
|
||||
@@ -354,32 +416,70 @@
|
||||
if(AIStatus != AI_ON)//Don't want mindless mobs to have their movement screwed up firing in space
|
||||
newtonian_move(get_dir(targeted_atom, targets_from))
|
||||
P.original = targeted_atom
|
||||
P.preparePixelProjectile(targeted_atom, get_turf(targeted_atom), src)
|
||||
P.fire()
|
||||
return P
|
||||
|
||||
/mob/living/simple_animal/hostile/proc/DestroySurroundings()
|
||||
/mob/living/simple_animal/hostile/proc/CanSmashTurfs(turf/T)
|
||||
return iswallturf(T) || ismineralturf(T)
|
||||
|
||||
/mob/living/simple_animal/hostile/Move(atom/newloc, dir , step_x , step_y)
|
||||
if(dodging && approaching_target && prob(dodge_prob) && moving_diagonally == 0 && isturf(loc) && isturf(newloc))
|
||||
return dodge(newloc, dir)
|
||||
else
|
||||
return ..()
|
||||
|
||||
/mob/living/simple_animal/hostile/proc/dodge(moving_to,move_direction)
|
||||
//Assuming we move towards the target we want to swerve toward them to get closer
|
||||
var/cdir = turn(move_direction, 45)
|
||||
var/ccdir = turn(move_direction, -45)
|
||||
dodging = FALSE
|
||||
. = Move(get_step(loc,pick(cdir,ccdir)))
|
||||
if(!.)//Can't dodge there so we just carry on
|
||||
. = Move(moving_to,move_direction)
|
||||
dodging = TRUE
|
||||
|
||||
/mob/living/simple_animal/hostile/proc/DestroyObjectsInDirection(direction)
|
||||
var/turf/T = get_step(targets_from, direction)
|
||||
if(QDELETED(T))
|
||||
return
|
||||
if(T.Adjacent(targets_from))
|
||||
if(CanSmashTurfs(T))
|
||||
T.attack_animal(src)
|
||||
return
|
||||
for(var/obj/O in T.contents)
|
||||
if(!O.Adjacent(targets_from))
|
||||
continue
|
||||
if((ismachinery(O) || isstructure(O)) && O.density && environment_smash >= ENVIRONMENT_SMASH_STRUCTURES && !O.IsObscured())
|
||||
O.attack_animal(src)
|
||||
return
|
||||
|
||||
/mob/living/simple_animal/hostile/proc/DestroyPathToTarget()
|
||||
if(environment_smash)
|
||||
EscapeConfinement()
|
||||
var/dir_to_target = get_dir(targets_from, target)
|
||||
var/dir_list = list()
|
||||
if(dir_to_target in diagonals) //it's diagonal, so we need two directions to hit
|
||||
for(var/direction in cardinal)
|
||||
if(direction & dir_to_target)
|
||||
dir_list += direction
|
||||
else
|
||||
dir_list += dir_to_target
|
||||
for(var/direction in dir_list) //now we hit all of the directions we got in this fashion, since it's the only directions we should actually need
|
||||
DestroyObjectsInDirection(direction)
|
||||
|
||||
/mob/living/simple_animal/hostile/proc/DestroySurroundings() // for use with megafauna destroying everything around them
|
||||
if(environment_smash)
|
||||
EscapeConfinement()
|
||||
for(var/dir in cardinal)
|
||||
var/turf/T = get_step(targets_from, dir)
|
||||
if(iswallturf(T) || ismineralturf(T))
|
||||
if(T.Adjacent(targets_from))
|
||||
T.attack_animal(src)
|
||||
for(var/a in T)
|
||||
var/atom/A = a
|
||||
if(!A.Adjacent(targets_from))
|
||||
continue
|
||||
if(is_type_in_typecache(A, environment_target_typecache))
|
||||
A.attack_animal(src)
|
||||
return
|
||||
DestroyObjectsInDirection(dir)
|
||||
|
||||
/mob/living/simple_animal/hostile/proc/EscapeConfinement()
|
||||
if(buckled)
|
||||
buckled.attack_animal(src)
|
||||
if(!isturf(targets_from.loc) && targets_from.loc != null)//Did someone put us in something?
|
||||
var/atom/A = get_turf(targets_from)
|
||||
var/atom/A = targets_from.loc
|
||||
A.attack_animal(src)//Bang on it till we get out
|
||||
return
|
||||
|
||||
/mob/living/simple_animal/hostile/proc/FindHidden()
|
||||
if(istype(target.loc, /obj/structure/closet) || istype(target.loc, /obj/machinery/disposal) || istype(target.loc, /obj/machinery/sleeper) || istype(target.loc, /obj/machinery/bodyscanner) || istype(target.loc, /obj/machinery/recharge_station))
|
||||
@@ -420,9 +520,23 @@
|
||||
LosePatience()
|
||||
lose_patience_timer_id = addtimer(CALLBACK(src, .proc/LoseTarget), lose_patience_timeout, TIMER_STOPPABLE)
|
||||
|
||||
|
||||
/mob/living/simple_animal/hostile/proc/LosePatience()
|
||||
deltimer(lose_patience_timer_id)
|
||||
|
||||
|
||||
//These two procs handle losing and regaining search_objects when attacked by a mob
|
||||
/mob/living/simple_animal/hostile/proc/LoseSearchObjects()
|
||||
search_objects = 0
|
||||
deltimer(search_objects_timer_id)
|
||||
search_objects_timer_id = addtimer(CALLBACK(src, .proc/RegainSearchObjects), search_objects_regain_time, TIMER_STOPPABLE)
|
||||
|
||||
|
||||
/mob/living/simple_animal/hostile/proc/RegainSearchObjects(value)
|
||||
if(!value)
|
||||
value = initial(search_objects)
|
||||
search_objects = value
|
||||
|
||||
/mob/living/simple_animal/hostile/consider_wakeup()
|
||||
..()
|
||||
var/list/tlist
|
||||
@@ -455,4 +569,4 @@
|
||||
if(isturf(M.loc))
|
||||
. += M
|
||||
else if(M.loc.type in hostile_machines)
|
||||
. += M.loc
|
||||
. += M.loc
|
||||
@@ -46,8 +46,8 @@
|
||||
|
||||
|
||||
/mob/living/simple_animal/hostile/illusion/AttackingTarget()
|
||||
..()
|
||||
if(istype(target, /mob/living) && prob(multiply_chance))
|
||||
. = ..()
|
||||
if(. && isliving(target) && prob(multiply_chance))
|
||||
var/mob/living/L = target
|
||||
if(L.stat == DEAD)
|
||||
return
|
||||
|
||||
@@ -23,6 +23,9 @@
|
||||
pixel_x = -16
|
||||
see_in_dark = 8
|
||||
|
||||
emote_taunt = list("nashes")
|
||||
taunt_chance = 20
|
||||
|
||||
harm_intent_damage = 8
|
||||
melee_damage_lower = 15
|
||||
melee_damage_upper = 15
|
||||
@@ -33,18 +36,13 @@
|
||||
var/stalk_tick_delay = 3
|
||||
gold_core_spawnable = CHEM_MOB_SPAWN_HOSTILE
|
||||
|
||||
/mob/living/simple_animal/hostile/panther/FindTarget(var/list/possible_targets)
|
||||
/mob/living/simple_animal/hostile/panther/AttackingTarget()
|
||||
. = ..()
|
||||
if(.)
|
||||
emote("nashes at [.]")
|
||||
|
||||
/mob/living/simple_animal/hostile/panther/AttackingTarget()
|
||||
. =..()
|
||||
var/mob/living/L = .
|
||||
if(istype(L))
|
||||
if(prob(15))
|
||||
L.Weaken(3)
|
||||
L.visible_message("<span class='danger'>\the [src] knocks down \the [L]!</span>")
|
||||
if(prob(15) && iscarbon(target))
|
||||
var/mob/living/carbon/C = target
|
||||
C.Weaken(3)
|
||||
C.visible_message("<span class='danger'>\the [src] knocks down \the [C]!</span>")
|
||||
|
||||
//*******//
|
||||
// Snake //
|
||||
@@ -67,6 +65,9 @@
|
||||
maxHealth = 25
|
||||
health = 25
|
||||
|
||||
emote_taunt = list("hisses wickedly")
|
||||
taunt_chance = 20
|
||||
|
||||
harm_intent_damage = 2
|
||||
melee_damage_lower = 3
|
||||
melee_damage_upper = 10
|
||||
@@ -77,13 +78,9 @@
|
||||
var/stalk_tick_delay = 3
|
||||
gold_core_spawnable = CHEM_MOB_SPAWN_HOSTILE
|
||||
|
||||
/mob/living/simple_animal/hostile/snake/FindTarget()
|
||||
. = ..()
|
||||
if(.)
|
||||
emote("hisses wickedly")
|
||||
|
||||
/mob/living/simple_animal/hostile/snake/AttackingTarget()
|
||||
. =..()
|
||||
var/mob/living/L = .
|
||||
if(istype(L))
|
||||
L.apply_damage(rand(3,12), TOX)
|
||||
if(.)
|
||||
if(iscarbon(target))
|
||||
var/mob/living/carbon/C = target
|
||||
C.apply_damage(rand(3, 12), TOX)
|
||||
|
||||
@@ -34,7 +34,7 @@ Difficulty: Medium
|
||||
move_to_delay = 3
|
||||
projectiletype = /obj/item/projectile/kinetic/miner
|
||||
projectilesound = 'sound/weapons/kenetic_accel.ogg'
|
||||
ranged = 1
|
||||
ranged = TRUE
|
||||
ranged_cooldown_time = 16
|
||||
pixel_x = -16
|
||||
crusher_loot = list(/obj/item/melee/energy/cleaving_saw, /obj/item/gun/energy/kinetic_accelerator, /obj/item/crusher_trophy/miner_eye)
|
||||
@@ -47,8 +47,12 @@ Difficulty: Medium
|
||||
var/dashing = FALSE
|
||||
var/dash_cooldown = 15
|
||||
var/guidance = FALSE
|
||||
var/transform_stop_attack = FALSE // stops the blood drunk miner from attacking after transforming his weapon until the next attack chain
|
||||
deathmessage = "falls to the ground, decaying into glowing particles."
|
||||
death_sound = "bodyfall"
|
||||
attack_action_types = list(/datum/action/innate/megafauna_attack/dash,
|
||||
/datum/action/innate/megafauna_attack/kinetic_accelerator,
|
||||
/datum/action/innate/megafauna_attack/transform_weapon)
|
||||
|
||||
/obj/item/gps/internal/miner
|
||||
icon_state = null
|
||||
@@ -56,13 +60,52 @@ Difficulty: Medium
|
||||
desc = "The sweet blood, oh, it sings to me."
|
||||
invisibility = 100
|
||||
|
||||
/mob/living/simple_animal/hostile/megafauna/blood_drunk_miner/guidance
|
||||
guidance = TRUE
|
||||
|
||||
/mob/living/simple_animal/hostile/megafauna/blood_drunk_miner/hunter/AttackingTarget()
|
||||
/mob/living/simple_animal/hostile/megafauna/blood_drunk_miner/Initialize(mapload)
|
||||
. = ..()
|
||||
if(. && prob(12))
|
||||
INVOKE_ASYNC(src, .proc/dash)
|
||||
miner_saw = new(src)
|
||||
internal_gps = new/obj/item/gps/internal/miner(src)
|
||||
|
||||
// Add a zone selection UI; otherwise the mob can't melee attack properly.
|
||||
zone_sel = new /obj/screen/zone_sel()
|
||||
|
||||
/datum/action/innate/megafauna_attack/dash
|
||||
name = "Dash To Target"
|
||||
icon_icon = 'icons/mob/actions/actions.dmi'
|
||||
button_icon_state = "sniper_zoom"
|
||||
chosen_message = "<span class='colossus'>You are now dashing to your target.</span>"
|
||||
chosen_attack_num = 1
|
||||
|
||||
/datum/action/innate/megafauna_attack/kinetic_accelerator
|
||||
name = "Fire Kinetic Accelerator"
|
||||
icon_icon = 'icons/obj/guns/energy.dmi'
|
||||
button_icon_state = "kineticgun"
|
||||
chosen_message = "<span class='colossus'>You are now shooting your kinetic accelerator.</span>"
|
||||
chosen_attack_num = 2
|
||||
|
||||
/datum/action/innate/megafauna_attack/transform_weapon
|
||||
name = "Transform Weapon"
|
||||
icon_icon = 'icons/obj/lavaland/artefacts.dmi'
|
||||
button_icon_state = "cleaving_saw"
|
||||
chosen_message = "<span class='colossus'>You are now transforming your weapon.</span>"
|
||||
chosen_attack_num = 3
|
||||
|
||||
/mob/living/simple_animal/hostile/megafauna/blood_drunk_miner/OpenFire()
|
||||
if(client)
|
||||
switch(chosen_attack)
|
||||
if(1)
|
||||
dash(target)
|
||||
if(2)
|
||||
shoot_ka()
|
||||
if(3)
|
||||
transform_weapon()
|
||||
return
|
||||
|
||||
Goto(target, move_to_delay, minimum_distance)
|
||||
if(get_dist(src, target) > MINER_DASH_RANGE && dash_cooldown <= world.time)
|
||||
dash_attack()
|
||||
else
|
||||
shoot_ka()
|
||||
transform_weapon()
|
||||
|
||||
/obj/item/melee/energy/cleaving_saw/miner //nerfed saw because it is very murdery
|
||||
force = 6
|
||||
@@ -79,15 +122,7 @@ Difficulty: Medium
|
||||
icon_state = "ka_tracer"
|
||||
range = MINER_DASH_RANGE
|
||||
|
||||
/mob/living/simple_animal/hostile/megafauna/blood_drunk_miner/Initialize()
|
||||
. = ..()
|
||||
miner_saw = new(src)
|
||||
internal_gps = new/obj/item/gps/internal/miner(src)
|
||||
|
||||
// Add a zone selection UI; otherwise the mob can't melee attack properly.
|
||||
zone_sel = new /obj/screen/zone_sel()
|
||||
|
||||
/mob/living/simple_animal/hostile/megafauna/blood_drunk_miner/adjustHealth(amount, updating_health = TRUE, forced = FALSE)
|
||||
/mob/living/simple_animal/hostile/megafauna/blood_drunk_miner/adjustHealth(amount, updating_health = TRUE)
|
||||
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
|
||||
@@ -104,16 +139,19 @@ Difficulty: Medium
|
||||
return FALSE
|
||||
return ..()
|
||||
|
||||
/mob/living/simple_animal/hostile/megafauna/blood_drunk_miner/ex_act(severity, target)
|
||||
/mob/living/simple_animal/hostile/megafauna/blood_drunk_miner/ex_act(severity)
|
||||
if(dash())
|
||||
return
|
||||
return ..()
|
||||
|
||||
/mob/living/simple_animal/hostile/megafauna/blood_drunk_miner/MeleeAction(patience = TRUE)
|
||||
transform_stop_attack = FALSE
|
||||
return ..()
|
||||
|
||||
/mob/living/simple_animal/hostile/megafauna/blood_drunk_miner/AttackingTarget()
|
||||
if(QDELETED(target))
|
||||
return
|
||||
if(next_move > world.time || !Adjacent(target)) //some cheating
|
||||
INVOKE_ASYNC(src, .proc/quick_attack_loop)
|
||||
if(client)
|
||||
transform_stop_attack = FALSE
|
||||
if(QDELETED(target) || transform_stop_attack)
|
||||
return
|
||||
face_atom(target)
|
||||
if(isliving(target))
|
||||
@@ -132,8 +170,6 @@ Difficulty: Medium
|
||||
miner_saw.melee_attack_chain(src, target)
|
||||
if(guidance)
|
||||
adjustHealth(-2)
|
||||
transform_weapon()
|
||||
INVOKE_ASYNC(src, .proc/quick_attack_loop)
|
||||
return TRUE
|
||||
|
||||
/mob/living/simple_animal/hostile/megafauna/blood_drunk_miner/do_attack_animation(atom/A, visual_effect_icon, obj/item/used_item, no_effect)
|
||||
@@ -146,16 +182,10 @@ Difficulty: Medium
|
||||
. = ..()
|
||||
if(. && target && !targets_the_same)
|
||||
wander = TRUE
|
||||
transform_weapon()
|
||||
INVOKE_ASYNC(src, .proc/quick_attack_loop)
|
||||
|
||||
/mob/living/simple_animal/hostile/megafauna/blood_drunk_miner/OpenFire()
|
||||
Goto(target, move_to_delay, minimum_distance)
|
||||
if(get_dist(src, target) > MINER_DASH_RANGE && dash_cooldown <= world.time)
|
||||
INVOKE_ASYNC(src, .proc/dash, target)
|
||||
else
|
||||
shoot_ka()
|
||||
transform_weapon()
|
||||
/mob/living/simple_animal/hostile/megafauna/blood_drunk_miner/proc/dash_attack()
|
||||
INVOKE_ASYNC(src, .proc/dash, target)
|
||||
shoot_ka()
|
||||
|
||||
/mob/living/simple_animal/hostile/megafauna/blood_drunk_miner/proc/shoot_ka()
|
||||
if(ranged_cooldown <= world.time && get_dist(src, target) <= MINER_DASH_RANGE && !Adjacent(target))
|
||||
@@ -166,21 +196,6 @@ Difficulty: Medium
|
||||
Shoot(target)
|
||||
changeNext_move(CLICK_CD_RANGE)
|
||||
|
||||
//I'm still of the belief that this entire proc needs to be wiped from existence.
|
||||
// do not take my touching of it to be endorsement of it. ~mso
|
||||
/mob/living/simple_animal/hostile/megafauna/blood_drunk_miner/proc/quick_attack_loop()
|
||||
while(!QDELETED(target) && next_move <= world.time) //this is done this way because next_move can change to be sooner while we sleep.
|
||||
stoplag(1)
|
||||
sleep((next_move - world.time) * 1.5) //but don't ask me what the fuck this is about
|
||||
if(QDELETED(target))
|
||||
return
|
||||
if(dashing || next_move > world.time || !Adjacent(target))
|
||||
if(dashing && next_move <= world.time)
|
||||
next_move = world.time + 1
|
||||
INVOKE_ASYNC(src, .proc/quick_attack_loop) //lets try that again.
|
||||
return
|
||||
AttackingTarget()
|
||||
|
||||
/mob/living/simple_animal/hostile/megafauna/blood_drunk_miner/proc/dash(atom/dash_target)
|
||||
if(world.time < dash_cooldown)
|
||||
return
|
||||
@@ -189,7 +204,9 @@ Difficulty: Medium
|
||||
var/turf/own_turf = get_turf(src)
|
||||
if(!QDELETED(dash_target))
|
||||
self_dist_to_target += get_dist(dash_target, own_turf)
|
||||
for(var/turf/simulated/O in RANGE_TURFS(MINER_DASH_RANGE, own_turf))
|
||||
for(var/turf/O in RANGE_TURFS(MINER_DASH_RANGE, own_turf))
|
||||
if(O.density)
|
||||
continue
|
||||
var/turf_dist_to_target = 0
|
||||
if(!QDELETED(dash_target))
|
||||
turf_dist_to_target += get_dist(dash_target, O)
|
||||
@@ -218,26 +235,29 @@ Difficulty: Medium
|
||||
var/turf/step_forward_turf = get_step(own_turf, get_cardinal_dir(own_turf, target_turf))
|
||||
new /obj/effect/temp_visual/small_smoke/halfsecond(step_back_turf)
|
||||
new /obj/effect/temp_visual/small_smoke/halfsecond(step_forward_turf)
|
||||
var/obj/effect/temp_visual/decoy/D = new /obj/effect/temp_visual/decoy(loc, src)
|
||||
animate(D, alpha = 0, time = 5)
|
||||
var/obj/effect/temp_visual/decoy/fading/halfsecond/D = new (own_turf, src)
|
||||
forceMove(step_back_turf)
|
||||
playsound(own_turf, 'sound/weapons/punchmiss.ogg', 40, 1, -1)
|
||||
dashing = TRUE
|
||||
alpha = 0
|
||||
animate(src, alpha = 255, time = 5)
|
||||
sleep(2)
|
||||
SLEEP_CHECK_DEATH(2)
|
||||
D.forceMove(step_forward_turf)
|
||||
forceMove(target_turf)
|
||||
playsound(target_turf, 'sound/weapons/punchmiss.ogg', 40, 1, -1)
|
||||
sleep(1)
|
||||
SLEEP_CHECK_DEATH(1)
|
||||
dashing = FALSE
|
||||
shoot_ka()
|
||||
return TRUE
|
||||
|
||||
/mob/living/simple_animal/hostile/megafauna/blood_drunk_miner/proc/transform_weapon()
|
||||
if(time_until_next_transform <= world.time)
|
||||
miner_saw.transform_cooldown = 0
|
||||
miner_saw.transform_weapon(src, TRUE)
|
||||
if(!miner_saw.active)
|
||||
rapid_melee = 5 // 4 deci cooldown before changes, npcpool subsystem wait is 20, 20/4 = 5
|
||||
else
|
||||
rapid_melee = 3 // same thing but halved (slightly rounded up)
|
||||
transform_stop_attack = TRUE
|
||||
icon_state = "miner[miner_saw.active ? "_transformed":""]"
|
||||
icon_living = "miner[miner_saw.active ? "_transformed":""]"
|
||||
time_until_next_transform = world.time + rand(50, 100)
|
||||
@@ -263,4 +283,12 @@ Difficulty: Medium
|
||||
sleep(4)
|
||||
animate(src, alpha = 0, time = 6, easing = EASE_OUT, flags = ANIMATION_PARALLEL)
|
||||
|
||||
/mob/living/simple_animal/hostile/megafauna/blood_drunk_miner/guidance
|
||||
guidance = TRUE
|
||||
|
||||
/mob/living/simple_animal/hostile/megafauna/blood_drunk_miner/hunter/AttackingTarget()
|
||||
. = ..()
|
||||
if(. && prob(12))
|
||||
INVOKE_ASYNC(src, .proc/dash)
|
||||
|
||||
#undef MINER_DASH_RANGE
|
||||
@@ -122,12 +122,16 @@ Difficulty: Hard
|
||||
|
||||
/mob/living/simple_animal/hostile/megafauna/bubblegum/AttackingTarget()
|
||||
if(!charging)
|
||||
..()
|
||||
return ..()
|
||||
|
||||
/mob/living/simple_animal/hostile/megafauna/bubblegum/Goto(target, delay, minimum_distance)
|
||||
if(!charging)
|
||||
..()
|
||||
|
||||
/mob/living/simple_animal/hostile/megafauna/bubblegum/MoveToTarget(list/possible_targets)
|
||||
if(!charging)
|
||||
..()
|
||||
|
||||
/mob/living/simple_animal/hostile/megafauna/bubblegum/Move()
|
||||
if(charging)
|
||||
new /obj/effect/temp_visual/decoy/fading(loc, src)
|
||||
@@ -195,7 +199,7 @@ Difficulty: Hard
|
||||
. = list()
|
||||
for(var/mob/living/L in targets)
|
||||
var/list/bloodpool = get_pools(get_turf(L), 0)
|
||||
if(bloodpool.len && (!faction_check(L) || L.stat == DEAD))
|
||||
if(bloodpool.len && (!faction_check_mob(L) || L.stat == DEAD))
|
||||
. += L
|
||||
|
||||
/mob/living/simple_animal/hostile/megafauna/bubblegum/proc/try_bloodattack()
|
||||
@@ -246,7 +250,7 @@ Difficulty: Hard
|
||||
new /obj/effect/temp_visual/bubblegum_hands/leftsmack(T)
|
||||
sleep(2.5)
|
||||
for(var/mob/living/L in T)
|
||||
if(!faction_check(L))
|
||||
if(!faction_check_mob(L))
|
||||
to_chat(L, "<span class='userdanger'>[src] rends you!</span>")
|
||||
playsound(T, attack_sound, 100, 1, -1)
|
||||
var/limb_to_hit = pick("head", "chest", "r_arm", "l_arm", "r_leg", "l_leg")
|
||||
@@ -262,7 +266,7 @@ Difficulty: Hard
|
||||
new /obj/effect/temp_visual/bubblegum_hands/leftthumb(T)
|
||||
sleep(6)
|
||||
for(var/mob/living/L in T)
|
||||
if(!faction_check(L))
|
||||
if(!faction_check_mob(L))
|
||||
to_chat(L, "<span class='userdanger'>[src] drags you through the blood!</span>")
|
||||
playsound(T, 'sound/misc/enter_blood.ogg', 100, 1, -1)
|
||||
var/turf/targetturf = get_step(src, dir)
|
||||
|
||||
@@ -62,14 +62,14 @@ Difficulty: Medium
|
||||
return
|
||||
..()
|
||||
|
||||
/mob/living/simple_animal/hostile/megafauna/dragon/adjustHealth(amount)
|
||||
/mob/living/simple_animal/hostile/megafauna/dragon/adjustHealth(amount, updating_health = TRUE)
|
||||
if(swooping)
|
||||
return 0
|
||||
return FALSE
|
||||
return ..()
|
||||
|
||||
/mob/living/simple_animal/hostile/megafauna/dragon/AttackingTarget()
|
||||
if(!swooping)
|
||||
..()
|
||||
return ..()
|
||||
|
||||
/mob/living/simple_animal/hostile/megafauna/dragon/DestroySurroundings()
|
||||
if(!swooping)
|
||||
|
||||
@@ -123,13 +123,18 @@ Difficulty: Hard
|
||||
adjustHealth(-L.maxHealth*0.5)
|
||||
L.dust()
|
||||
|
||||
/mob/living/simple_animal/hostile/megafauna/hierophant/CanAttack(atom/the_target)
|
||||
. = ..()
|
||||
if(istype(the_target, /mob/living/simple_animal/hostile/asteroid/hivelordbrood)) //ignore temporary targets in favor of more permanent targets
|
||||
return FALSE
|
||||
|
||||
/*/mob/living/simple_animal/hostile/megafauna/hierophant/GiveTarget(new_target)
|
||||
var/targets_the_same = (new_target == target)
|
||||
. = ..()
|
||||
if(. && target && !targets_the_same)
|
||||
visible_message("<span class='hierophant'>\"[pick(target_phrases)]\"</span>")*/
|
||||
|
||||
/mob/living/simple_animal/hostile/megafauna/hierophant/adjustHealth(amount)
|
||||
/mob/living/simple_animal/hostile/megafauna/hierophant/adjustHealth(amount, updating_health = TRUE)
|
||||
. = ..()
|
||||
if(src && amount > 0 && !blinking)
|
||||
wander = TRUE
|
||||
@@ -140,7 +145,7 @@ Difficulty: Hard
|
||||
if(target && isliving(target))
|
||||
spawn(0)
|
||||
melee_blast(get_turf(target)) //melee attacks on living mobs produce a 3x3 blast
|
||||
..()
|
||||
return ..()
|
||||
|
||||
/mob/living/simple_animal/hostile/megafauna/hierophant/DestroySurroundings()
|
||||
if(!blinking)
|
||||
@@ -536,7 +541,7 @@ Difficulty: Hard
|
||||
/obj/effect/temp_visual/hierophant/blast/proc/do_damage(turf/T)
|
||||
for(var/mob/living/L in T.contents - hit_things) //find and damage mobs...
|
||||
hit_things += L
|
||||
if((friendly_fire_check && caster && caster.faction_check(L)) || L.stat == DEAD)
|
||||
if((friendly_fire_check && caster && caster.faction_check_mob(L)) || L.stat == DEAD)
|
||||
continue
|
||||
if(L.client)
|
||||
flash_color(L.client, "#660099", 1)
|
||||
@@ -551,7 +556,7 @@ Difficulty: Hard
|
||||
for(var/obj/mecha/M in T.contents - hit_things) //and mechs.
|
||||
hit_things += M
|
||||
if(M.occupant)
|
||||
if(friendly_fire_check && caster && caster.faction_check(M.occupant))
|
||||
if(friendly_fire_check && caster && caster.faction_check_mob(M.occupant))
|
||||
continue
|
||||
to_chat(M.occupant, "<span class='userdanger'>Your [M.name] is struck by a [name]!</span>")
|
||||
playsound(M,'sound/weapons/sear.ogg', 50, 1, -4)
|
||||
|
||||
@@ -46,7 +46,6 @@ Difficulty: Medium
|
||||
loot = list(/obj/item/stack/sheet/bone = 3)
|
||||
vision_range = 13
|
||||
elimination = 1
|
||||
idle_vision_range = 13
|
||||
appearance_flags = 0
|
||||
mouse_opacity = MOUSE_OPACITY_ICON
|
||||
stat_attack = 1 // Overriden from /tg/ - otherwise Legion starts chasing its minions
|
||||
@@ -56,8 +55,8 @@ Difficulty: Medium
|
||||
internal_gps = new/obj/item/gps/internal/legion(src)
|
||||
|
||||
/mob/living/simple_animal/hostile/megafauna/legion/AttackingTarget()
|
||||
..()
|
||||
if(ishuman(target))
|
||||
. = ..()
|
||||
if(. && ishuman(target))
|
||||
var/mob/living/L = target
|
||||
if(L.stat == UNCONSCIOUS)
|
||||
var/mob/living/simple_animal/hostile/asteroid/hivelordbrood/legion/A = new(loc)
|
||||
|
||||
@@ -18,19 +18,8 @@
|
||||
damage_coeff = list(BRUTE = 1, BURN = 0.5, TOX = 1, CLONE = 1, STAMINA = 0, OXY = 1)
|
||||
minbodytemp = 0
|
||||
maxbodytemp = INFINITY
|
||||
vision_range = 5
|
||||
aggro_vision_range = 18
|
||||
idle_vision_range = 5
|
||||
environment_target_typecache = list(
|
||||
/obj/machinery/door/window,
|
||||
/obj/structure/window,
|
||||
/obj/structure/closet,
|
||||
/obj/structure/table,
|
||||
/obj/structure/grille,
|
||||
/obj/structure/girder,
|
||||
/obj/structure/rack,
|
||||
/obj/structure/barricade,
|
||||
/obj/machinery/field,
|
||||
/obj/machinery/power/emitter)
|
||||
var/list/crusher_loot
|
||||
var/medal_type
|
||||
var/score_type = BOSS_SCORE
|
||||
@@ -43,10 +32,15 @@
|
||||
mob_size = MOB_SIZE_LARGE
|
||||
layer = LARGE_MOB_LAYER //Looks weird with them slipping under mineral walls and cameras and shit otherwise
|
||||
mouse_opacity = MOUSE_OPACITY_OPAQUE // Easier to click on in melee, they're giant targets anyway
|
||||
var/chosen_attack = 1 // chosen attack num
|
||||
var/list/attack_action_types = list()
|
||||
|
||||
/mob/living/simple_animal/hostile/megafauna/New()
|
||||
..()
|
||||
apply_status_effect(STATUS_EFFECT_CRUSHERDAMAGETRACKING)
|
||||
for(var/action_type in attack_action_types)
|
||||
var/datum/action/innate/megafauna_attack/attack_action = new action_type()
|
||||
attack_action.Grant(src)
|
||||
|
||||
/mob/living/simple_animal/hostile/megafauna/Destroy()
|
||||
QDEL_NULL(internal_gps)
|
||||
@@ -70,8 +64,8 @@
|
||||
loot = crusher_loot
|
||||
|
||||
/mob/living/simple_animal/hostile/megafauna/AttackingTarget()
|
||||
..()
|
||||
if(isliving(target))
|
||||
. = ..()
|
||||
if(. && isliving(target))
|
||||
var/mob/living/L = target
|
||||
if(L.stat != DEAD)
|
||||
if(!client && ranged && ranged_cooldown <= world.time)
|
||||
@@ -124,3 +118,21 @@
|
||||
SSmedals.SetScore(BOSS_SCORE, C, 1)
|
||||
SSmedals.SetScore(score_type, C, 1)
|
||||
return TRUE
|
||||
|
||||
/datum/action/innate/megafauna_attack
|
||||
name = "Megafauna Attack"
|
||||
icon_icon = 'icons/mob/actions/actions_animal.dmi'
|
||||
button_icon_state = ""
|
||||
var/mob/living/simple_animal/hostile/megafauna/M
|
||||
var/chosen_message
|
||||
var/chosen_attack_num = 0
|
||||
|
||||
/datum/action/innate/megafauna_attack/Grant(mob/living/L)
|
||||
if(istype(L, /mob/living/simple_animal/hostile/megafauna))
|
||||
M = L
|
||||
return ..()
|
||||
return FALSE
|
||||
|
||||
/datum/action/innate/megafauna_attack/Activate()
|
||||
M.chosen_attack = chosen_attack_num
|
||||
to_chat(M, chosen_message)
|
||||
@@ -81,7 +81,7 @@ GLOBAL_LIST_INIT(AISwarmerCapsByType, list(/mob/living/simple_animal/hostile/swa
|
||||
new createtype(loc)
|
||||
|
||||
|
||||
/mob/living/simple_animal/hostile/megafauna/swarmer_swarm_beacon/adjustHealth(amount, updating_health = TRUE, forced = FALSE)
|
||||
/mob/living/simple_animal/hostile/megafauna/swarmer_swarm_beacon/adjustHealth(amount, updating_health = TRUE)
|
||||
. = ..()
|
||||
if(. > 0 && world.time > call_help_cooldown)
|
||||
call_help_cooldown = world.time + call_help_cooldown_amt
|
||||
|
||||
@@ -17,7 +17,9 @@
|
||||
melee_damage_upper = 12
|
||||
attacktext = "attacks"
|
||||
attack_sound = 'sound/weapons/bite.ogg'
|
||||
emote_taunt = list("growls")
|
||||
speak_emote = list("creaks")
|
||||
taunt_chance = 30
|
||||
|
||||
atmos_requirements = list("min_oxy" = 0, "max_oxy" = 0, "min_tox" = 0, "max_tox" = 0, "min_co2" = 0, "max_co2" = 0, "min_n2" = 0, "max_n2" = 0)
|
||||
minbodytemp = 0
|
||||
@@ -29,11 +31,6 @@
|
||||
gold_core_spawnable = CHEM_MOB_SPAWN_HOSTILE
|
||||
del_on_death = 1
|
||||
|
||||
/mob/living/simple_animal/hostile/mimic/FindTarget()
|
||||
. = ..()
|
||||
if(.)
|
||||
custom_emote(1, "growls at [.]")
|
||||
|
||||
/mob/living/simple_animal/hostile/mimic/emp_act(severity)
|
||||
if(is_electronic)
|
||||
switch(severity)
|
||||
@@ -56,7 +53,7 @@
|
||||
for(var/obj/item/I in loc)
|
||||
I.loc = src
|
||||
|
||||
/mob/living/simple_animal/hostile/mimic/crate/DestroySurroundings()
|
||||
/mob/living/simple_animal/hostile/mimic/crate/DestroyPathToTarget()
|
||||
..()
|
||||
if(prob(90))
|
||||
icon_state = "[initial(icon_state)]open"
|
||||
@@ -77,15 +74,19 @@
|
||||
. = ..()
|
||||
if(.)
|
||||
icon_state = initial(icon_state)
|
||||
if(prob(15) && iscarbon(target))
|
||||
var/mob/living/carbon/C = target
|
||||
C.Weaken(2)
|
||||
C.visible_message("<span class='danger'>\The [src] knocks down \the [C]!</span>", "<span class='userdanger'>\The [src] knocks you down!</span>")
|
||||
|
||||
/mob/living/simple_animal/hostile/mimic/crate/proc/trigger()
|
||||
if(!attempt_open)
|
||||
visible_message("<b>[src]</b> starts to move!")
|
||||
attempt_open = 1
|
||||
|
||||
/mob/living/simple_animal/hostile/mimic/crate/adjustHealth(damage)
|
||||
/mob/living/simple_animal/hostile/mimic/crate/adjustHealth(amount, updating_health = TRUE)
|
||||
trigger()
|
||||
..(damage)
|
||||
. = ..()
|
||||
|
||||
/mob/living/simple_animal/hostile/mimic/crate/LoseTarget()
|
||||
..()
|
||||
@@ -96,18 +97,10 @@
|
||||
var/obj/structure/closet/crate/C = new(get_turf(src))
|
||||
// Put loot in crate
|
||||
for(var/obj/O in src)
|
||||
O.loc = C
|
||||
O.forceMove(C)
|
||||
// due to `del_on_death`
|
||||
return ..()
|
||||
|
||||
/mob/living/simple_animal/hostile/mimic/crate/AttackingTarget()
|
||||
. =..()
|
||||
var/mob/living/L = .
|
||||
if(istype(L))
|
||||
if(prob(15))
|
||||
L.Weaken(2)
|
||||
L.visible_message("<span class='danger'>\the [src] knocks down \the [L]!</span>")
|
||||
|
||||
var/global/list/protected_objects = list(/obj/structure/table, /obj/structure/cable, /obj/structure/window)
|
||||
|
||||
/mob/living/simple_animal/hostile/mimic/copy
|
||||
@@ -191,14 +184,11 @@ var/global/list/protected_objects = list(/obj/structure/table, /obj/structure/ca
|
||||
..()
|
||||
|
||||
/mob/living/simple_animal/hostile/mimic/copy/AttackingTarget()
|
||||
..()
|
||||
if(knockdown_people)
|
||||
if(iscarbon(target))
|
||||
var/mob/living/carbon/C = target
|
||||
if(prob(15))
|
||||
C.Weaken(2)
|
||||
C.visible_message("<span class='danger'>\The [src] knocks down \the [C]!</span>", \
|
||||
"<span class='userdanger'>\The [src] knocks you down!</span>")
|
||||
. = ..()
|
||||
if(knockdown_people && . && prob(15) && iscarbon(target))
|
||||
var/mob/living/carbon/C = target
|
||||
C.Weaken(2)
|
||||
C.visible_message("<span class='danger'>\The [src] knocks down \the [C]!</span>", "<span class='userdanger'>\The [src] knocks you down!</span>")
|
||||
|
||||
/mob/living/simple_animal/hostile/mimic/copy/Aggro()
|
||||
..()
|
||||
|
||||
@@ -26,8 +26,8 @@
|
||||
a_intent = INTENT_HARM
|
||||
speak_emote = list("chitters")
|
||||
attack_sound = 'sound/weapons/bladeslice.ogg'
|
||||
vision_range = 2
|
||||
aggro_vision_range = 9
|
||||
idle_vision_range = 2
|
||||
turns_per_move = 5
|
||||
loot = list(/obj/item/stack/ore/diamond{layer = 4.1},
|
||||
/obj/item/stack/ore/diamond{layer = 4.1})
|
||||
@@ -41,13 +41,10 @@
|
||||
flag = "energy"
|
||||
temperature = 50
|
||||
|
||||
/mob/living/simple_animal/hostile/asteroid/basilisk/GiveTarget(var/new_target)
|
||||
/mob/living/simple_animal/hostile/asteroid/basilisk/GiveTarget(new_target)
|
||||
if(..()) //we have a target
|
||||
if(isliving(target))
|
||||
var/mob/living/L = target
|
||||
if(L.bodytemperature > 261)
|
||||
L.bodytemperature = 261
|
||||
visible_message("<span class='danger'>The [src.name]'s stare chills [L.name] to the bone!</span>")
|
||||
if(isliving(target) && !target.Adjacent(targets_from) && ranged_cooldown <= world.time)//No more being shot at point blank or spammed with RNG beams
|
||||
OpenFire(target)
|
||||
|
||||
/mob/living/simple_animal/hostile/asteroid/basilisk/ex_act(severity)
|
||||
switch(severity)
|
||||
|
||||
@@ -8,8 +8,8 @@
|
||||
icon_dead = "Goldgrub_dead"
|
||||
icon_gib = "syndicate_gib"
|
||||
vision_range = 2
|
||||
vision_range = 2
|
||||
aggro_vision_range = 9
|
||||
idle_vision_range = 2
|
||||
move_to_delay = 5
|
||||
friendly = "harmlessly rolls into"
|
||||
maxHealth = 45
|
||||
@@ -48,14 +48,13 @@
|
||||
retreat_distance = 10
|
||||
minimum_distance = 10
|
||||
if(will_burrow)
|
||||
spawn(chase_time)
|
||||
Burrow()
|
||||
addtimer(CALLBACK(src, .proc/Burrow), chase_time)
|
||||
|
||||
/mob/living/simple_animal/hostile/asteroid/goldgrub/AttackingTarget()
|
||||
if(istype(target, /obj/item/stack/ore))
|
||||
EatOre(target)
|
||||
return
|
||||
..()
|
||||
return ..()
|
||||
|
||||
/mob/living/simple_animal/hostile/asteroid/goldgrub/proc/EatOre(var/atom/targeted_ore)
|
||||
for(var/obj/item/stack/ore/O in get_turf(targeted_ore))
|
||||
@@ -69,13 +68,13 @@
|
||||
|
||||
/mob/living/simple_animal/hostile/asteroid/goldgrub/proc/Burrow()//Begin the chase to kill the goldgrub in time
|
||||
if(!stat)
|
||||
visible_message("<span class='danger'>The [src.name] buries into the ground, vanishing from sight!</span>")
|
||||
visible_message("<span class='danger'>The [name] buries into the ground, vanishing from sight!</span>")
|
||||
qdel(src)
|
||||
|
||||
/mob/living/simple_animal/hostile/asteroid/goldgrub/bullet_act(obj/item/projectile/P)
|
||||
visible_message("<span class='danger'>The [P.name] was repelled by [src.name]'s girth!</span>")
|
||||
return
|
||||
|
||||
/mob/living/simple_animal/hostile/asteroid/goldgrub/adjustHealth(damage)
|
||||
idle_vision_range = 9
|
||||
/mob/living/simple_animal/hostile/asteroid/goldgrub/adjustHealth(amount, updating_health = TRUE)
|
||||
vision_range = 9
|
||||
. = ..()
|
||||
|
||||
@@ -11,7 +11,6 @@
|
||||
mouse_opacity = MOUSE_OPACITY_OPAQUE
|
||||
move_to_delay = 40
|
||||
ranged = TRUE
|
||||
ranged_cooldown = 2 //By default, start the Goliath with his cooldown off so that people can run away quickly on first sight
|
||||
ranged_cooldown_time = 120
|
||||
friendly = "wails at"
|
||||
speak_emote = list("bellows")
|
||||
@@ -26,8 +25,8 @@
|
||||
attacktext = "pulverizes"
|
||||
attack_sound = 'sound/weapons/punch1.ogg'
|
||||
throw_message = "does nothing to the rocky hide of the"
|
||||
vision_range = 5
|
||||
aggro_vision_range = 9
|
||||
idle_vision_range = 5
|
||||
move_force = MOVE_FORCE_VERY_STRONG
|
||||
move_resist = MOVE_FORCE_VERY_STRONG
|
||||
pull_force = MOVE_FORCE_VERY_STRONG
|
||||
@@ -54,6 +53,8 @@
|
||||
|
||||
/mob/living/simple_animal/hostile/asteroid/goliath/OpenFire()
|
||||
var/tturf = get_turf(target)
|
||||
if(!isturf(tturf))
|
||||
return
|
||||
if(get_dist(src, target) <= 7)//Screen range check, so you can't get tentacle'd offscreen
|
||||
visible_message("<span class='warning'>The [src.name] digs its tentacles under [target.name]!</span>")
|
||||
new /obj/effect/temp_visual/goliath_tentacle/original(tturf, src)
|
||||
@@ -61,10 +62,10 @@
|
||||
icon_state = icon_aggro
|
||||
pre_attack = FALSE
|
||||
|
||||
/mob/living/simple_animal/hostile/asteroid/goliath/adjustHealth(damage)
|
||||
ranged_cooldown--
|
||||
/mob/living/simple_animal/hostile/asteroid/goliath/adjustHealth(amount, updating_health = TRUE)
|
||||
ranged_cooldown -= 10
|
||||
handle_preattack()
|
||||
..()
|
||||
. = ..()
|
||||
|
||||
/mob/living/simple_animal/hostile/asteroid/goliath/Aggro()
|
||||
vision_range = aggro_vision_range
|
||||
@@ -188,4 +189,4 @@
|
||||
/obj/effect/temp_visual/goliath_tentacle/proc/retract()
|
||||
icon_state = "Goliath_tentacle_retract"
|
||||
deltimer(timerid)
|
||||
timerid = QDEL_IN(src, 5)
|
||||
timerid = QDEL_IN(src, 7)
|
||||
|
||||
@@ -30,7 +30,7 @@
|
||||
stop_automated_movement_when_pulled = TRUE
|
||||
stat_exclusive = TRUE
|
||||
robust_searching = TRUE
|
||||
search_objects = TRUE
|
||||
search_objects = 3
|
||||
del_on_death = TRUE
|
||||
loot = list(/obj/effect/decal/cleanable/blood/gibs)
|
||||
deathmessage = "is pulped into bugmash."
|
||||
@@ -38,7 +38,7 @@
|
||||
animal_species = /mob/living/simple_animal/hostile/asteroid/gutlunch
|
||||
childtype = list(/mob/living/simple_animal/hostile/asteroid/gutlunch/gubbuck = 45, /mob/living/simple_animal/hostile/asteroid/gutlunch/guthen = 55)
|
||||
|
||||
wanted_objects = list(/obj/effect/decal/cleanable/blood/gibs)
|
||||
wanted_objects = list(/obj/effect/decal/cleanable/blood/gibs, /obj/item/organ/internal)
|
||||
var/obj/item/udder/gutlunch/udder = null
|
||||
|
||||
/mob/living/simple_animal/hostile/asteroid/gutlunch/New()
|
||||
@@ -61,16 +61,37 @@
|
||||
udder.milkAnimal(O, user)
|
||||
regenerate_icons()
|
||||
else
|
||||
..()
|
||||
return ..()
|
||||
|
||||
/mob/living/simple_animal/hostile/asteroid/gutlunch/CanAttack(atom/the_target) // Gutlunch-specific version of CanAttack to handle stupid stat_exclusive = true crap so we don't have to do it for literally every single simple_animal/hostile except the two that spawn in lavaland
|
||||
if(isturf(the_target) || !the_target || the_target.type == /atom/movable/lighting_object) // bail out on invalids
|
||||
return FALSE
|
||||
|
||||
if(see_invisible < the_target.invisibility)//Target's invisible to us, forget it
|
||||
return FALSE
|
||||
|
||||
if(isliving(the_target))
|
||||
var/mob/living/L = the_target
|
||||
|
||||
if(faction_check_mob(L) && !attack_same)
|
||||
return FALSE
|
||||
if(L.stat > stat_attack || L.stat != stat_attack && stat_exclusive)
|
||||
return FALSE
|
||||
|
||||
return TRUE
|
||||
|
||||
if(isobj(the_target) && is_type_in_typecache(the_target, wanted_objects))
|
||||
return TRUE
|
||||
|
||||
return FALSE
|
||||
|
||||
/mob/living/simple_animal/hostile/asteroid/gutlunch/AttackingTarget()
|
||||
if(is_type_in_typecache(target, wanted_objects)) //we eats
|
||||
if(is_type_in_typecache(target,wanted_objects)) //we eats
|
||||
udder.generateMilk()
|
||||
regenerate_icons()
|
||||
visible_message("<span class='notice'>[src] slurps up [target].</span>")
|
||||
qdel(target)
|
||||
return
|
||||
..()
|
||||
return ..()
|
||||
|
||||
/obj/item/udder/gutlunch
|
||||
name = "nutrient sac"
|
||||
|
||||
@@ -11,8 +11,8 @@
|
||||
move_to_delay = 14
|
||||
ranged = 1
|
||||
vision_range = 5
|
||||
vision_range = 5
|
||||
aggro_vision_range = 9
|
||||
idle_vision_range = 5
|
||||
speed = 3
|
||||
maxHealth = 75
|
||||
health = 75
|
||||
@@ -44,6 +44,7 @@
|
||||
|
||||
/mob/living/simple_animal/hostile/asteroid/hivelord/AttackingTarget()
|
||||
OpenFire()
|
||||
return TRUE
|
||||
|
||||
/mob/living/simple_animal/hostile/asteroid/hivelord/spawn_crusher_loot()
|
||||
loot += crusher_loot //we don't butcher
|
||||
|
||||
@@ -28,12 +28,14 @@
|
||||
|
||||
/mob/living/simple_animal/hostile/asteroid/Aggro()
|
||||
..()
|
||||
icon_state = icon_aggro
|
||||
if(vision_range != aggro_vision_range)
|
||||
icon_state = icon_aggro
|
||||
|
||||
/mob/living/simple_animal/hostile/asteroid/LoseAggro()
|
||||
..()
|
||||
if(stat == CONSCIOUS)
|
||||
icon_state = icon_living
|
||||
if(stat == DEAD)
|
||||
return
|
||||
icon_state = icon_living
|
||||
|
||||
/mob/living/simple_animal/hostile/asteroid/bullet_act(var/obj/item/projectile/P)//Reduces damage from most projectiles to curb off-screen kills
|
||||
if(!stat)
|
||||
|
||||
@@ -1,225 +0,0 @@
|
||||
/mob/living/simple_animal/hostile/asteroid/
|
||||
vision_range = 2
|
||||
atmos_requirements = list("min_oxy" = 0, "max_oxy" = 0, "min_tox" = 0, "max_tox" = 0, "min_co2" = 0, "max_co2" = 0, "min_n2" = 0, "max_n2" = 0)
|
||||
unsuitable_atmos_damage = 15
|
||||
faction = list("mining")
|
||||
weather_immunities = list("lava","ash")
|
||||
obj_damage = 30
|
||||
environment_smash = 2
|
||||
minbodytemp = 0
|
||||
heat_damage_per_tick = 20
|
||||
response_help = "pokes"
|
||||
response_disarm = "shoves"
|
||||
response_harm = "strikes"
|
||||
status_flags = 0
|
||||
a_intent = INTENT_HARM
|
||||
var/throw_message = "bounces off of"
|
||||
var/icon_aggro = null // for swapping to when we get aggressive
|
||||
see_in_dark = 8
|
||||
lighting_alpha = LIGHTING_PLANE_ALPHA_MOSTLY_INVISIBLE
|
||||
mob_size = MOB_SIZE_LARGE
|
||||
|
||||
/mob/living/simple_animal/hostile/asteroid/Aggro()
|
||||
..()
|
||||
icon_state = icon_aggro
|
||||
|
||||
/mob/living/simple_animal/hostile/asteroid/LoseAggro()
|
||||
..()
|
||||
if(stat == CONSCIOUS)
|
||||
icon_state = icon_living
|
||||
|
||||
/mob/living/simple_animal/hostile/asteroid/bullet_act(var/obj/item/projectile/P)//Reduces damage from most projectiles to curb off-screen kills
|
||||
if(!stat)
|
||||
Aggro()
|
||||
if(P.damage < 30 && P.damage_type != BRUTE)
|
||||
P.damage = (P.damage / 3)
|
||||
visible_message("<span class='danger'>The [P] has a reduced effect on [src]!</span>")
|
||||
..()
|
||||
|
||||
/mob/living/simple_animal/hostile/asteroid/hitby(atom/movable/AM)//No floor tiling them to death, wiseguy
|
||||
if(istype(AM, /obj/item))
|
||||
var/obj/item/T = AM
|
||||
if(!stat)
|
||||
Aggro()
|
||||
if(T.throwforce <= 20)
|
||||
visible_message("<span class='notice'>The [T.name] [src.throw_message] [src.name]!</span>")
|
||||
return
|
||||
..()
|
||||
|
||||
/mob/living/simple_animal/hostile/asteroid/basilisk
|
||||
name = "basilisk"
|
||||
desc = "A territorial beast, covered in a thick shell that absorbs energy. Its stare causes victims to freeze from the inside."
|
||||
icon = 'icons/mob/animal.dmi'
|
||||
icon_state = "Basilisk"
|
||||
icon_living = "Basilisk"
|
||||
icon_aggro = "Basilisk_alert"
|
||||
icon_dead = "Basilisk_dead"
|
||||
icon_gib = "syndicate_gib"
|
||||
move_to_delay = 20
|
||||
projectiletype = /obj/item/projectile/temp/basilisk
|
||||
projectilesound = 'sound/weapons/pierce.ogg'
|
||||
ranged = 1
|
||||
ranged_message = "stares"
|
||||
ranged_cooldown_time = 30
|
||||
throw_message = "does nothing against the hard shell of"
|
||||
vision_range = 2
|
||||
speed = 3
|
||||
maxHealth = 200
|
||||
health = 200
|
||||
harm_intent_damage = 5
|
||||
obj_damage = 60
|
||||
melee_damage_lower = 12
|
||||
melee_damage_upper = 12
|
||||
attacktext = "bites into"
|
||||
a_intent = INTENT_HARM
|
||||
speak_emote = list("chitters")
|
||||
attack_sound = 'sound/weapons/bladeslice.ogg'
|
||||
aggro_vision_range = 9
|
||||
idle_vision_range = 2
|
||||
turns_per_move = 5
|
||||
loot = list(/obj/item/stack/ore/diamond{layer = 4.1},
|
||||
/obj/item/stack/ore/diamond{layer = 4.1})
|
||||
|
||||
/obj/item/projectile/temp/basilisk
|
||||
name = "freezing blast"
|
||||
icon_state = "ice_2"
|
||||
damage = 0
|
||||
damage_type = BURN
|
||||
nodamage = 1
|
||||
flag = "energy"
|
||||
temperature = 50
|
||||
|
||||
/mob/living/simple_animal/hostile/asteroid/basilisk/GiveTarget(var/new_target)
|
||||
if(..()) //we have a target
|
||||
if(isliving(target))
|
||||
var/mob/living/L = target
|
||||
if(L.bodytemperature > 261)
|
||||
L.bodytemperature = 261
|
||||
visible_message("<span class='danger'>The [src.name]'s stare chills [L.name] to the bone!</span>")
|
||||
|
||||
/mob/living/simple_animal/hostile/asteroid/basilisk/ex_act(severity)
|
||||
switch(severity)
|
||||
if(1.0)
|
||||
gib()
|
||||
if(2.0)
|
||||
adjustBruteLoss(140)
|
||||
if(3.0)
|
||||
adjustBruteLoss(110)
|
||||
|
||||
/mob/living/simple_animal/hostile/asteroid/goliath
|
||||
name = "goliath"
|
||||
desc = "A massive beast that uses long tentacles to ensare its prey, threatening them is not advised under any conditions."
|
||||
icon = 'icons/mob/animal.dmi'
|
||||
icon_state = "Goliath"
|
||||
icon_living = "Goliath"
|
||||
icon_aggro = "Goliath_alert"
|
||||
icon_dead = "Goliath_dead"
|
||||
icon_gib = "syndicate_gib"
|
||||
attack_sound = 'sound/weapons/punch4.ogg'
|
||||
mouse_opacity = MOUSE_OPACITY_OPAQUE
|
||||
move_to_delay = 40
|
||||
ranged = 1
|
||||
ranged_cooldown = 2 //By default, start the Goliath with his cooldown off so that people can run away quickly on first sight
|
||||
ranged_cooldown_time = 120
|
||||
friendly = "wails at"
|
||||
speak_emote = list("bellows")
|
||||
vision_range = 4
|
||||
speed = 3
|
||||
maxHealth = 300
|
||||
health = 300
|
||||
harm_intent_damage = 1 //Only the manliest of men can kill a Goliath with only their fists.
|
||||
obj_damage = 100
|
||||
melee_damage_lower = 25
|
||||
melee_damage_upper = 25
|
||||
attacktext = "pulverizes"
|
||||
attack_sound = 'sound/weapons/punch1.ogg'
|
||||
throw_message = "does nothing to the rocky hide of the"
|
||||
aggro_vision_range = 9
|
||||
idle_vision_range = 5
|
||||
move_force = MOVE_FORCE_VERY_STRONG
|
||||
move_resist = MOVE_FORCE_VERY_STRONG
|
||||
pull_force = MOVE_FORCE_VERY_STRONG
|
||||
var/pre_attack = 0
|
||||
loot = list(/obj/item/stack/sheet/animalhide/goliath_hide{layer = ABOVE_MOB_LAYER})
|
||||
|
||||
/mob/living/simple_animal/hostile/asteroid/goliath/Life()
|
||||
..()
|
||||
handle_preattack()
|
||||
|
||||
/mob/living/simple_animal/hostile/asteroid/goliath/proc/handle_preattack()
|
||||
if(ranged_cooldown <= world.time + ranged_cooldown_time * 0.25 && !pre_attack)
|
||||
pre_attack++
|
||||
if(!pre_attack || stat || AIStatus == AI_IDLE)
|
||||
return
|
||||
icon_state = "Goliath_preattack"
|
||||
|
||||
/mob/living/simple_animal/hostile/asteroid/goliath/revive()
|
||||
move_force = MOVE_FORCE_VERY_STRONG
|
||||
move_resist = MOVE_FORCE_VERY_STRONG
|
||||
pull_force = MOVE_FORCE_VERY_STRONG
|
||||
..()
|
||||
|
||||
/mob/living/simple_animal/hostile/asteroid/goliath/OpenFire()
|
||||
var/tturf = get_turf(target)
|
||||
if(get_dist(src, target) <= 7)//Screen range check, so you can't get tentacle'd offscreen
|
||||
visible_message("<span class='warning'>The [src.name] digs its tentacles under [target.name]!</span>")
|
||||
new /obj/effect/goliath_tentacle/original(tturf)
|
||||
ranged_cooldown = world.time + ranged_cooldown_time
|
||||
icon_state = icon_aggro
|
||||
pre_attack = 0
|
||||
return
|
||||
|
||||
/mob/living/simple_animal/hostile/asteroid/goliath/adjustHealth(damage)
|
||||
ranged_cooldown--
|
||||
handle_preattack()
|
||||
..()
|
||||
|
||||
/mob/living/simple_animal/hostile/asteroid/goliath/Aggro()
|
||||
vision_range = aggro_vision_range
|
||||
handle_preattack()
|
||||
if(icon_state != icon_aggro)
|
||||
icon_state = icon_aggro
|
||||
return
|
||||
|
||||
/obj/effect/goliath_tentacle/
|
||||
name = "Goliath tentacle"
|
||||
icon = 'icons/mob/animal.dmi'
|
||||
icon_state = "Goliath_tentacle"
|
||||
var/latched = 0
|
||||
|
||||
/obj/effect/goliath_tentacle/New()
|
||||
var/turftype = get_turf(src)
|
||||
if(istype(turftype, /turf/simulated/mineral))
|
||||
var/turf/simulated/mineral/M = turftype
|
||||
M.gets_drilled()
|
||||
spawn(20)
|
||||
Trip()
|
||||
|
||||
/obj/effect/goliath_tentacle/original
|
||||
|
||||
/obj/effect/goliath_tentacle/original/New()
|
||||
for(var/obj/effect/goliath_tentacle/original/O in loc)//No more GG NO RE from 2+ goliaths simultaneously tentacling you
|
||||
if(O != src)
|
||||
qdel(src)
|
||||
var/list/directions = cardinal.Copy()
|
||||
var/counter
|
||||
for(counter = 1, counter <= 3, counter++)
|
||||
var/spawndir = pick(directions)
|
||||
directions -= spawndir
|
||||
var/turf/T = get_step(src,spawndir)
|
||||
new /obj/effect/goliath_tentacle(T)
|
||||
..()
|
||||
|
||||
|
||||
/obj/effect/goliath_tentacle/proc/Trip()
|
||||
for(var/mob/living/M in src.loc)
|
||||
M.Stun(5)
|
||||
M.adjustBruteLoss(rand(10,15))
|
||||
latched = 1
|
||||
if(src && M)
|
||||
visible_message("<span class='danger'>The [src.name] grabs hold of [M.name]!</span>")
|
||||
if(!latched)
|
||||
qdel(src)
|
||||
else
|
||||
spawn(50)
|
||||
qdel(src)
|
||||
@@ -61,21 +61,42 @@
|
||||
health = maxHealth
|
||||
..()
|
||||
|
||||
/mob/living/simple_animal/hostile/mushroom/adjustHealth(damage)//Possibility to flee from a fight just to make it more visually interesting
|
||||
/mob/living/simple_animal/hostile/mushroom/CanAttack(atom/the_target) // Mushroom-specific version of CanAttack to handle stupid attack_same = 2 crap so we don't have to do it for literally every single simple_animal/hostile because this shit never gets spawned
|
||||
if(!the_target || isturf(the_target) || istype(the_target, /atom/movable/lighting_object))
|
||||
return FALSE
|
||||
|
||||
if(see_invisible < the_target.invisibility)//Target's invisible to us, forget it
|
||||
return FALSE
|
||||
|
||||
if(isliving(the_target))
|
||||
var/mob/living/L = the_target
|
||||
|
||||
if (!faction_check_mob(L) && attack_same == 2)
|
||||
return FALSE
|
||||
if(L.stat > stat_attack)
|
||||
return FALSE
|
||||
|
||||
return TRUE
|
||||
|
||||
return FALSE
|
||||
|
||||
/mob/living/simple_animal/hostile/mushroom/adjustHealth(amount, updating_health = TRUE)//Possibility to flee from a fight just to make it more visually interesting
|
||||
if(!retreat_distance && prob(33))
|
||||
retreat_distance = 5
|
||||
spawn(30)
|
||||
retreat_distance = null
|
||||
..()
|
||||
addtimer(CALLBACK(src, .proc/stop_retreat), 30)
|
||||
. = ..()
|
||||
|
||||
/mob/living/simple_animal/hostile/mushroom/attack_animal(var/mob/living/L)
|
||||
/mob/living/simple_animal/hostile/mushroom/proc/stop_retreat()
|
||||
retreat_distance = null
|
||||
|
||||
/mob/living/simple_animal/hostile/mushroom/attack_animal(mob/living/L)
|
||||
if(istype(L, /mob/living/simple_animal/hostile/mushroom) && stat == DEAD)
|
||||
var/mob/living/simple_animal/hostile/mushroom/M = L
|
||||
if(faint_ticker < 2)
|
||||
M.visible_message("<span class='notice'>[M] chews a bit on [src].</span>")
|
||||
M.visible_message("[M] chews a bit on [src].")
|
||||
faint_ticker++
|
||||
return
|
||||
M.visible_message("<span class='notice'>[M] devours [src]!</span>")
|
||||
return TRUE
|
||||
M.visible_message("<span class='warning'>[M] devours [src]!</span>")
|
||||
var/level_gain = (powerlevel - M.powerlevel)
|
||||
if(level_gain >= -1 && !bruised && !M.ckey)//Player shrooms can't level up to become robust gods.
|
||||
if(level_gain < 1)//So we still gain a level if two mushrooms were the same level
|
||||
@@ -83,7 +104,8 @@
|
||||
M.LevelUp(level_gain)
|
||||
M.adjustBruteLoss(-M.maxHealth)
|
||||
qdel(src)
|
||||
..()
|
||||
return TRUE
|
||||
return ..()
|
||||
|
||||
/mob/living/simple_animal/hostile/mushroom/revive()
|
||||
..()
|
||||
|
||||
@@ -36,7 +36,7 @@
|
||||
icon_dead = "piratemelee_dead"
|
||||
projectilesound = 'sound/weapons/laser.ogg'
|
||||
ranged = 1
|
||||
rapid = 1
|
||||
rapid = 2
|
||||
retreat_distance = 5
|
||||
minimum_distance = 5
|
||||
projectiletype = /obj/item/projectile/beam
|
||||
|
||||
@@ -7,7 +7,7 @@
|
||||
icon_living = "drone3"
|
||||
icon_dead = "drone_dead"
|
||||
ranged = 1
|
||||
rapid = 1
|
||||
rapid = 3
|
||||
speak_chance = 5
|
||||
turns_per_move = 3
|
||||
response_help = "pokes the"
|
||||
|
||||
@@ -1,20 +1,20 @@
|
||||
/mob/living/simple_animal/hostile/retaliate
|
||||
var/list/enemies = list()
|
||||
|
||||
/mob/living/simple_animal/hostile/retaliate/Found(var/atom/A)
|
||||
/mob/living/simple_animal/hostile/retaliate/Found(atom/A)
|
||||
if(isliving(A))
|
||||
var/mob/living/L = A
|
||||
if(!L.stat)
|
||||
return L
|
||||
else
|
||||
enemies -= L
|
||||
else if(istype(A, /obj/mecha))
|
||||
else if(ismecha(A))
|
||||
var/obj/mecha/M = A
|
||||
if(M.occupant)
|
||||
return A
|
||||
else if(istype(A, /obj/spacepod))
|
||||
var/obj/spacepod/M = A
|
||||
if(M.pilot)
|
||||
else if(isspacepod(A))
|
||||
var/obj/spacepod/S = A
|
||||
if(S.pilot)
|
||||
return A
|
||||
|
||||
/mob/living/simple_animal/hostile/retaliate/ListTargets()
|
||||
@@ -25,48 +25,32 @@
|
||||
return see
|
||||
|
||||
/mob/living/simple_animal/hostile/retaliate/proc/Retaliate()
|
||||
..()
|
||||
var/list/around = view(src, 7)
|
||||
var/list/around = view(src, vision_range)
|
||||
|
||||
for(var/atom/movable/A in around)
|
||||
if(A == src)
|
||||
continue
|
||||
if(isliving(A))
|
||||
var/mob/living/M = A
|
||||
var/faction_check = 0
|
||||
for(var/F in faction)
|
||||
if(F in M.faction)
|
||||
faction_check = 1
|
||||
break
|
||||
if(faction_check && attack_same || !faction_check)
|
||||
if(faction_check_mob(M) && attack_same || !faction_check_mob(M))
|
||||
enemies |= M
|
||||
else if(istype(A, /obj/mecha))
|
||||
else if(ismecha(A))
|
||||
var/obj/mecha/M = A
|
||||
if(M.occupant)
|
||||
enemies |= M
|
||||
enemies |= M.occupant
|
||||
else if(istype(A, /obj/spacepod))
|
||||
var/obj/spacepod/M = A
|
||||
if(M.pilot)
|
||||
enemies |= M
|
||||
enemies |= M.pilot
|
||||
else if(isspacepod(A))
|
||||
var/obj/spacepod/S = A
|
||||
if(S.pilot)
|
||||
enemies |= S
|
||||
enemies |= S.pilot
|
||||
|
||||
for(var/mob/living/simple_animal/hostile/retaliate/H in around)
|
||||
var/retaliate_faction_check = 0
|
||||
for(var/F in faction)
|
||||
if(F in H.faction)
|
||||
retaliate_faction_check = 1
|
||||
break
|
||||
if(retaliate_faction_check && !attack_same && !H.attack_same)
|
||||
if(faction_check_mob(H) && !attack_same && !H.attack_same)
|
||||
H.enemies |= enemies
|
||||
return 0
|
||||
|
||||
/mob/living/simple_animal/hostile/retaliate/adjustHealth(damage)
|
||||
..(damage)
|
||||
Retaliate()
|
||||
|
||||
/mob/living/simple_animal/hostile/retaliate/DestroySurroundings()
|
||||
for(var/dir in cardinal) // North, South, East, West
|
||||
var/obj/structure/obstacle = locate(/obj/structure, get_step(src, dir))
|
||||
if(istype(obstacle, /obj/structure/closet) || istype(obstacle, /obj/structure/table))
|
||||
obstacle.attack_animal(src)
|
||||
/mob/living/simple_animal/hostile/retaliate/adjustHealth(amount, updating_health = TRUE)
|
||||
. = ..()
|
||||
if(amount > 0 && stat == CONSCIOUS)
|
||||
Retaliate()
|
||||
@@ -35,6 +35,9 @@
|
||||
maxHealth = 20
|
||||
health = 20
|
||||
|
||||
emote_taunt = list("wails")
|
||||
taunt_chance = 20
|
||||
|
||||
harm_intent_damage = 10
|
||||
melee_damage_lower = 2
|
||||
melee_damage_upper = 3
|
||||
@@ -51,11 +54,6 @@
|
||||
/mob/living/simple_animal/hostile/retaliate/ghost/Process_Spacemove(var/check_drift = 0)
|
||||
return 1
|
||||
|
||||
/mob/living/simple_animal/hostile/retaliate/ghost/FindTarget()
|
||||
. = ..()
|
||||
if(.)
|
||||
custom_emote(1, "wails at [.]")
|
||||
|
||||
/mob/living/simple_animal/hostile/retaliate/ghost/Life(seconds, times_fired)
|
||||
if(target)
|
||||
invisibility = pick(0,0,60,invisibility)
|
||||
|
||||
@@ -33,6 +33,7 @@
|
||||
ranged = 1
|
||||
retreat_distance = 5
|
||||
minimum_distance = 5
|
||||
projectilesound = 'sound/weapons/gunshots/gunshot.ogg'
|
||||
casingtype = /obj/item/ammo_casing/a357
|
||||
loot = list(/obj/effect/mob_spawn/human/corpse/russian/ranged, /obj/item/gun/projectile/revolver/mateba)
|
||||
|
||||
|
||||
@@ -118,8 +118,9 @@
|
||||
|
||||
//Try to move onto target's turf and eat them
|
||||
/mob/living/simple_animal/hostile/spaceWorm/wormHead/AttackingTarget()
|
||||
..()
|
||||
attemptToEat(target)
|
||||
. = ..()
|
||||
if(.)
|
||||
attemptToEat(target)
|
||||
|
||||
//Attempt to eat things we bump into, Mobs, Walls, Clowns
|
||||
/mob/living/simple_animal/hostile/spaceWorm/wormHead/Bump(atom/obstacle)
|
||||
|
||||
@@ -36,7 +36,6 @@
|
||||
see_in_dark = 8
|
||||
vision_range = 12
|
||||
aggro_vision_range = 12
|
||||
idle_vision_range = 12
|
||||
|
||||
search_objects = 1 // So that it can see through walls
|
||||
|
||||
@@ -87,11 +86,11 @@
|
||||
if(can_be_seen(get_turf(loc)))
|
||||
if(client)
|
||||
to_chat(src, "<span class='warning'>You cannot attack, there are eyes on you!</span>")
|
||||
return
|
||||
return FALSE
|
||||
else
|
||||
..()
|
||||
return ..()
|
||||
|
||||
/mob/living/simple_animal/hostile/statue/DestroySurroundings()
|
||||
/mob/living/simple_animal/hostile/statue/DestroyPathToTarget()
|
||||
if(!can_be_seen(get_turf(loc)))
|
||||
..()
|
||||
|
||||
|
||||
@@ -135,6 +135,8 @@
|
||||
LoseTarget()
|
||||
|
||||
/mob/living/simple_animal/hostile/syndicate/melee/autogib/depot/handle_automated_action()
|
||||
if(!..())
|
||||
return
|
||||
if(seen_enemy)
|
||||
aggro_cycles++
|
||||
if(alert_on_timeout && !raised_alert && aggro_cycles >= 60)
|
||||
@@ -159,14 +161,13 @@
|
||||
continue
|
||||
if(depotarea.list_includes(body, depotarea.dead_list))
|
||||
continue
|
||||
if(faction_check(body))
|
||||
if(faction_check_mob(body))
|
||||
continue
|
||||
say("Target [body]... terminated.")
|
||||
depotarea.list_add(body, depotarea.dead_list)
|
||||
pointed(body)
|
||||
else
|
||||
scan_cycles++
|
||||
..()
|
||||
|
||||
/mob/living/simple_animal/hostile/syndicate/melee/autogib/depot/proc/raise_alert(var/reason)
|
||||
if(istype(depotarea) && (!raised_alert || seen_revived_enemy) && !depotarea.used_self_destruct)
|
||||
@@ -190,7 +191,7 @@
|
||||
/mob/living/simple_animal/hostile/syndicate/melee/autogib/depot/CanPass(atom/movable/mover, turf/target, height=0)
|
||||
if(isliving(mover))
|
||||
var/mob/living/blocker = mover
|
||||
if(faction_check(blocker))
|
||||
if(faction_check_mob(blocker))
|
||||
return 1
|
||||
return ..(mover, target, height)
|
||||
|
||||
@@ -256,11 +257,12 @@
|
||||
|
||||
/mob/living/simple_animal/hostile/syndicate/ranged
|
||||
ranged = 1
|
||||
rapid = 1
|
||||
rapid = 2
|
||||
retreat_distance = 5
|
||||
minimum_distance = 5
|
||||
icon_state = "syndicateranged"
|
||||
icon_living = "syndicateranged"
|
||||
projectilesound = 'sound/weapons/gunshots/gunshot.ogg'
|
||||
casingtype = /obj/item/ammo_casing/c45
|
||||
loot = list(/obj/effect/mob_spawn/human/corpse/syndicatesoldier, /obj/item/gun/projectile/automatic/c20r)
|
||||
|
||||
|
||||
@@ -20,7 +20,7 @@
|
||||
idle_ventcrawl_chance = 0
|
||||
ai_playercontrol_allowtype = 0
|
||||
ai_type = TS_AI_AGGRESSIVE
|
||||
rapid = 1
|
||||
rapid = 3
|
||||
canlay = 1000
|
||||
spider_tier = TS_TIER_5
|
||||
projectiletype = /obj/item/projectile/terrorqueenspit/empress
|
||||
|
||||
@@ -23,7 +23,7 @@
|
||||
regen_points_per_hp = 2 // 50% higher regen speed
|
||||
stat_attack = 1 // ensures they will target people in crit, too!
|
||||
wander = 0 // wandering defeats the purpose of stealth
|
||||
idle_vision_range = 3 // very low idle vision range
|
||||
vision_range = 3 // very low idle vision range
|
||||
delay_web = 20 // double speed
|
||||
web_type = /obj/structure/spider/terrorweb/gray
|
||||
|
||||
@@ -58,7 +58,7 @@
|
||||
if(invisibility > 0)
|
||||
GrayDeCloak()
|
||||
else
|
||||
..()
|
||||
return ..()
|
||||
|
||||
/mob/living/simple_animal/hostile/poison/terror_spider/proc/GrayCloak()
|
||||
visible_message("<span class='notice'>[src] hides in the vent.</span>")
|
||||
@@ -67,7 +67,6 @@
|
||||
icon_living = "terror_gray_cloaked"
|
||||
if(!ckey)
|
||||
vision_range = 3
|
||||
idle_vision_range = 3
|
||||
// Bugged, does not work yet. Also spams webs. Also doesn't look great. But... planned.
|
||||
move_to_delay = 15 // while invisible, slow.
|
||||
|
||||
@@ -76,7 +75,6 @@
|
||||
icon_state = "terror_gray"
|
||||
icon_living = "terror_gray"
|
||||
vision_range = 9
|
||||
idle_vision_range = 9
|
||||
move_to_delay = 5
|
||||
prob_ai_hides_in_vents = 10
|
||||
|
||||
|
||||
@@ -58,7 +58,7 @@
|
||||
visible_message("<span class='notice'>[src] retracts its fangs a little.</span>")
|
||||
melee_damage_lower = melee_damage_lower_rage1
|
||||
melee_damage_upper = melee_damage_upper_rage1
|
||||
..()
|
||||
return ..()
|
||||
|
||||
|
||||
/obj/structure/spider/terrorweb/red
|
||||
|
||||
@@ -11,7 +11,6 @@
|
||||
layer = 2.75
|
||||
health = 3
|
||||
var/stillborn = FALSE
|
||||
faction = list("terrorspiders")
|
||||
var/spider_myqueen = null
|
||||
var/spider_mymother = null
|
||||
var/goto_mother = FALSE
|
||||
@@ -169,10 +168,8 @@
|
||||
if(!grow_as)
|
||||
grow_as = pick(/mob/living/simple_animal/hostile/poison/terror_spider/red, /mob/living/simple_animal/hostile/poison/terror_spider/gray, /mob/living/simple_animal/hostile/poison/terror_spider/green)
|
||||
var/mob/living/simple_animal/hostile/poison/terror_spider/S = new grow_as(loc)
|
||||
S.faction = faction
|
||||
S.spider_myqueen = spider_myqueen
|
||||
S.spider_mymother = spider_mymother
|
||||
S.master_commander = master_commander
|
||||
S.enemies = enemies
|
||||
qdel(src)
|
||||
|
||||
@@ -186,10 +183,8 @@
|
||||
var/obj/structure/spider/eggcluster/terror_eggcluster/C = new /obj/structure/spider/eggcluster/terror_eggcluster(get_turf(src))
|
||||
C.spiderling_type = lay_type
|
||||
C.spiderling_number = lay_number
|
||||
C.faction = faction
|
||||
C.spider_myqueen = spider_myqueen
|
||||
C.spider_mymother = src
|
||||
C.master_commander = master_commander
|
||||
C.enemies = enemies
|
||||
if(spider_growinstantly)
|
||||
C.amount_grown = 250
|
||||
@@ -202,7 +197,6 @@
|
||||
desc = "A cluster of tiny spider eggs. They pulse with a strong inner life, and appear to have sharp thorns on the sides."
|
||||
icon_state = "eggs"
|
||||
var/spider_growinstantly = 0
|
||||
faction = list("terrorspiders")
|
||||
var/spider_myqueen = null
|
||||
var/spider_mymother = null
|
||||
var/spiderling_type = null
|
||||
@@ -244,10 +238,8 @@
|
||||
var/obj/structure/spider/spiderling/terror_spiderling/S = new /obj/structure/spider/spiderling/terror_spiderling(get_turf(src))
|
||||
if(spiderling_type)
|
||||
S.grow_as = spiderling_type
|
||||
S.faction = faction
|
||||
S.spider_myqueen = spider_myqueen
|
||||
S.spider_mymother = spider_mymother
|
||||
S.master_commander = master_commander
|
||||
S.enemies = enemies
|
||||
if(spider_growinstantly)
|
||||
S.amount_grown = 250
|
||||
|
||||
@@ -92,7 +92,7 @@ var/global/list/ts_spiderling_list = list()
|
||||
var/degenerate = 0 // if 1, they slowly degen until they all die off. Used by high-level abilities only.
|
||||
|
||||
// Vision
|
||||
idle_vision_range = 10
|
||||
vision_range = 10
|
||||
aggro_vision_range = 10
|
||||
see_in_dark = 8
|
||||
lighting_alpha = LIGHTING_PLANE_ALPHA_MOSTLY_INVISIBLE
|
||||
@@ -364,7 +364,7 @@ var/global/list/ts_spiderling_list = list()
|
||||
to_chat(T, "<span class='terrorspider'>TerrorSense: [msgtext]</span>")
|
||||
|
||||
/mob/living/simple_animal/hostile/poison/terror_spider/proc/CheckFaction()
|
||||
if(faction.len != 1 || (!("terrorspiders" in faction)) || master_commander != null)
|
||||
if(faction.len != 2 || (!("terrorspiders" in faction)) || master_commander != null)
|
||||
to_chat(src, "<span class='userdanger'>Your connection to the hive mind has been severed!</span>")
|
||||
log_runtime(EXCEPTION("Terror spider with incorrect faction list at: [atom_loc_line(src)]"))
|
||||
gib()
|
||||
|
||||
@@ -24,6 +24,8 @@
|
||||
attacktext = "bites"
|
||||
attack_sound = 'sound/weapons/bite.ogg'
|
||||
speak_emote = list("pines")
|
||||
emote_taunt = list("growls")
|
||||
taunt_chance = 20
|
||||
|
||||
atmos_requirements = list("min_oxy" = 0, "max_oxy" = 0, "min_tox" = 0, "max_tox" = 0, "min_co2" = 0, "max_co2" = 0, "min_n2" = 0, "max_n2" = 0)
|
||||
minbodytemp = 0
|
||||
@@ -34,15 +36,10 @@
|
||||
deathmessage = "is hacked into pieces!"
|
||||
del_on_death = 1
|
||||
|
||||
/mob/living/simple_animal/hostile/tree/FindTarget()
|
||||
. = ..()
|
||||
if(.)
|
||||
custom_emote(1, "growls at [.]")
|
||||
|
||||
/mob/living/simple_animal/hostile/tree/AttackingTarget()
|
||||
. =..()
|
||||
var/mob/living/L = .
|
||||
if(istype(L))
|
||||
. = ..()
|
||||
if(. && iscarbon(target))
|
||||
var/mob/living/carbon/C = target
|
||||
if(prob(15))
|
||||
L.Weaken(3)
|
||||
L.visible_message("<span class='danger'>\the [src] knocks down \the [L]!</span>")
|
||||
C.Weaken(3)
|
||||
C.visible_message("<span class='danger'>\the [src] knocks down \the [C]!</span>")
|
||||
@@ -90,7 +90,7 @@
|
||||
if(grasping.len < max_grasps)
|
||||
grasping:
|
||||
for(var/mob/living/L in view(grasp_range, src))
|
||||
if(L == src || faction_check(L) || (L in grasping) || L == target)
|
||||
if(L == src || faction_check_mob(L) || (L in grasping) || L == target)
|
||||
continue
|
||||
for(var/t in getline(src,L))
|
||||
for(var/a in t)
|
||||
@@ -105,6 +105,12 @@
|
||||
|
||||
|
||||
/mob/living/simple_animal/hostile/venus_human_trap/OpenFire(atom/the_target)
|
||||
for(var/turf/T in getline(src,target))
|
||||
if (T.density)
|
||||
return
|
||||
for(var/obj/O in T)
|
||||
if(O.density)
|
||||
return
|
||||
var/dist = get_dist(src,the_target)
|
||||
Beam(the_target, "vine", time=dist*2, maxdistance=dist+2, beam_type=/obj/effect/ebeam/vine)
|
||||
the_target.attack_animal(src)
|
||||
|
||||
@@ -117,7 +117,7 @@
|
||||
maxHealth = 250
|
||||
health = 250
|
||||
ranged = 1
|
||||
rapid = 1
|
||||
rapid = 3
|
||||
speed = 0 //he's lost some weight from the fighting
|
||||
projectiletype = /obj/item/projectile/ornament
|
||||
retreat_distance = 3
|
||||
|
||||
@@ -3,15 +3,17 @@
|
||||
icon = 'icons/mob/animal.dmi'
|
||||
health = 20
|
||||
maxHealth = 20
|
||||
gender = PLURAL //placeholder
|
||||
|
||||
universal_understand = 1
|
||||
universal_speak = 0
|
||||
status_flags = CANPUSH
|
||||
|
||||
var/icon_living = ""
|
||||
var/icon_dead = ""
|
||||
var/icon_resting = ""
|
||||
var/icon_gib = null //We only try to show a gibbing animation if this exists.
|
||||
|
||||
var/healable = 1
|
||||
var/flip_on_death = FALSE //Flip the sprite upside down on death. Mostly here for things lacking custom dead sprites.
|
||||
|
||||
var/list/speak = list()
|
||||
var/speak_chance = 0
|
||||
@@ -20,7 +22,6 @@
|
||||
|
||||
var/turns_per_move = 1
|
||||
var/turns_since_move = 0
|
||||
universal_speak = 0
|
||||
var/stop_automated_movement = 0 //Use this to temporarely stop random movement or to if you write special movement code for animals.
|
||||
var/wander = 1 // Does the mob wander around when idle?
|
||||
var/stop_automated_movement_when_pulled = 1 //When set to 1 this stops the animal from moving when someone is pulling it.
|
||||
@@ -38,11 +39,13 @@
|
||||
var/heat_damage_per_tick = 3 //amount of damage applied if animal's body temperature is higher than maxbodytemp
|
||||
var/cold_damage_per_tick = 2 //same as heat_damage_per_tick, only if the bodytemperature it's lower than minbodytemp
|
||||
|
||||
//Healable by medical stacks? Defaults to yes.
|
||||
var/healable = 1
|
||||
|
||||
//Atmos effect - Yes, you can make creatures that require plasma or co2 to survive. N2O is a trace gas and handled separately, hence why it isn't here. It'd be hard to add it. Hard and me don't mix (Yes, yes make all the dick jokes you want with that.) - Errorage
|
||||
var/list/atmos_requirements = list("min_oxy" = 5, "max_oxy" = 0, "min_tox" = 0, "max_tox" = 1, "min_co2" = 0, "max_co2" = 5, "min_n2" = 0, "max_n2" = 0) //Leaving something at 0 means it's off - has no maximum
|
||||
var/unsuitable_atmos_damage = 2 //This damage is taken when atmos doesn't fit all the requirements above
|
||||
|
||||
|
||||
//LETTING SIMPLE ANIMALS ATTACK? WHAT COULD GO WRONG. Defaults to zero so Ian can still be cuddly
|
||||
var/melee_damage_lower = 0
|
||||
var/melee_damage_upper = 0
|
||||
@@ -53,7 +56,7 @@
|
||||
var/attacktext = "attacks"
|
||||
var/attack_sound = null
|
||||
var/friendly = "nuzzles" //If the mob does no damage with it's attack
|
||||
var/environment_smash = 0 //Set to 1 to allow breaking of crates,lockers,racks,tables; 2 for walls; 3 for Rwalls
|
||||
var/environment_smash = ENVIRONMENT_SMASH_NONE //Set to 1 to allow breaking of crates,lockers,racks,tables; 2 for walls; 3 for Rwalls
|
||||
|
||||
var/speed = 1 //LETS SEE IF I CAN SET SPEEDS FOR SIMPLE MOBS WITHOUT DESTROYING EVERYTHING. Higher speed is slower, negative speed is faster
|
||||
var/can_hide = 0
|
||||
@@ -66,6 +69,7 @@
|
||||
var/next_scan_time = 0
|
||||
var/animal_species //Sorry, no spider+corgi buttbabies.
|
||||
|
||||
var/buffed = 0 //In the event that you want to have a buffing effect on the mob, but don't want it to stack with other effects, any outside force that applies a buff to a simple mob should at least set this to 1, so we have something to check against
|
||||
var/gold_core_spawnable = CHEM_MOB_SPAWN_INVALID //if CHEM_MOB_SPAWN_HOSTILE can be spawned by plasma with gold core, CHEM_MOB_SPAWN_FRIENDLY are 'friendlies' spawned with blood
|
||||
|
||||
var/mob/living/carbon/human/master_commander = null //holding var for determining who own/controls a sentient simple animal (for sentience potions).
|
||||
@@ -73,20 +77,35 @@
|
||||
var/mob/living/simple_animal/hostile/spawner/nest
|
||||
|
||||
var/sentience_type = SENTIENCE_ORGANIC // Sentience type, for slime potions
|
||||
|
||||
var/list/loot = list() //list of things spawned at mob's loc when it dies
|
||||
var/del_on_death = 0 //causes mob to be deleted on death, useful for mobs that spawn lootable corpses
|
||||
var/attacked_sound = "punch"
|
||||
var/deathmessage = ""
|
||||
var/death_sound = null //The sound played on death
|
||||
|
||||
var/allow_movement_on_non_turfs = FALSE
|
||||
|
||||
var/attacked_sound = "punch"
|
||||
|
||||
var/AIStatus = AI_ON //The Status of our AI, can be set to AI_ON (On, usual processing), AI_IDLE (Will not process, but will return to AI_ON if an enemy comes near), AI_OFF (Off, Not processing ever)
|
||||
var/can_have_ai = TRUE //once we have become sentient, we can never go back
|
||||
|
||||
var/shouldwakeup = FALSE //convenience var for forcibly waking up an idling AI on next check.
|
||||
|
||||
//domestication
|
||||
var/tame = 0
|
||||
|
||||
/mob/living/simple_animal/Initialize()
|
||||
..()
|
||||
var/my_z // I don't want to confuse this with client registered_z
|
||||
|
||||
/mob/living/simple_animal/Initialize(mapload)
|
||||
. = ..()
|
||||
GLOB.simple_animals[AIStatus] += src
|
||||
if(gender == PLURAL)
|
||||
gender = pick(MALE, FEMALE)
|
||||
if(!real_name)
|
||||
real_name = name
|
||||
if(!loc)
|
||||
stack_trace("Simple animal being instantiated in nullspace")
|
||||
verbs -= /mob/verb/observe
|
||||
if(!can_hide)
|
||||
verbs -= /mob/living/simple_animal/verb/hide
|
||||
@@ -114,27 +133,25 @@
|
||||
|
||||
return ..()
|
||||
|
||||
/mob/living/simple_animal/Login()
|
||||
if(src && src.client)
|
||||
src.client.screen = list()
|
||||
client.screen += client.void
|
||||
..()
|
||||
/mob/living/simple_animal/examine(mob/user)
|
||||
. = ..()
|
||||
if(stat == DEAD)
|
||||
to_chat(user, "<span class='deadsay'>Upon closer examination, [p_they()] appear[p_s()] to be dead.</span>")
|
||||
|
||||
/mob/living/simple_animal/updatehealth(reason = "none given")
|
||||
..(reason)
|
||||
health = Clamp(health, 0, maxHealth)
|
||||
med_hud_set_status()
|
||||
|
||||
/mob/living/simple_animal/lay_down()
|
||||
/mob/living/simple_animal/StartResting(updating = 1)
|
||||
..()
|
||||
handle_resting_state_icons()
|
||||
if(icon_resting && stat != DEAD)
|
||||
icon_state = icon_resting
|
||||
|
||||
/mob/living/simple_animal/proc/handle_resting_state_icons()
|
||||
if(icon_resting)
|
||||
if(resting && stat != DEAD)
|
||||
icon_state = icon_resting
|
||||
else if(stat != DEAD)
|
||||
icon_state = icon_living
|
||||
/mob/living/simple_animal/StopResting(updating = 1)
|
||||
..()
|
||||
if(icon_resting && stat != DEAD)
|
||||
icon_state = icon_living
|
||||
|
||||
/mob/living/simple_animal/update_stat(reason = "none given")
|
||||
if(status_flags & GODMODE)
|
||||
@@ -147,11 +164,13 @@
|
||||
create_debug_log("died of damage, trigger reason: [reason]")
|
||||
|
||||
/mob/living/simple_animal/proc/handle_automated_action()
|
||||
set waitfor = FALSE
|
||||
return
|
||||
|
||||
/mob/living/simple_animal/proc/handle_automated_movement()
|
||||
set waitfor = FALSE
|
||||
if(!stop_automated_movement && wander)
|
||||
if(isturf(src.loc) && !resting && !buckled && canmove) //This is so it only moves if it's not inside a closet, gentics machine, etc.
|
||||
if((isturf(loc) || allow_movement_on_non_turfs) && !resting && !buckled && canmove) //This is so it only moves if it's not inside a closet, gentics machine, etc.
|
||||
turns_since_move++
|
||||
if(turns_since_move >= turns_per_move)
|
||||
if(!(stop_automated_movement_when_pulled && pulledby)) //Soma animals don't move when pulled
|
||||
@@ -159,11 +178,12 @@
|
||||
if(Process_Spacemove(anydir))
|
||||
Move(get_step(src,anydir), anydir)
|
||||
turns_since_move = 0
|
||||
return
|
||||
return 1
|
||||
|
||||
/mob/living/simple_animal/proc/handle_automated_speech()
|
||||
/mob/living/simple_animal/proc/handle_automated_speech(override)
|
||||
set waitfor = FALSE
|
||||
if(speak_chance)
|
||||
if(rand(0,200) < speak_chance)
|
||||
if(prob(speak_chance) || override)
|
||||
if(speak && speak.len)
|
||||
if((emote_hear && emote_hear.len) || (emote_see && emote_see.len))
|
||||
var/length = speak.len
|
||||
@@ -201,7 +221,7 @@
|
||||
|
||||
var/areatemp = get_temperature(environment)
|
||||
|
||||
if(abs(areatemp - bodytemperature) > 40 && !(BREATHLESS in mutations))
|
||||
if(abs(areatemp - bodytemperature) > 5 && !(BREATHLESS in mutations))
|
||||
var/diff = areatemp - bodytemperature
|
||||
diff = diff / 5
|
||||
bodytemperature += diff
|
||||
@@ -242,30 +262,24 @@
|
||||
atmos_suitable = 0
|
||||
|
||||
if(!atmos_suitable)
|
||||
adjustBruteLoss(unsuitable_atmos_damage)
|
||||
adjustHealth(unsuitable_atmos_damage)
|
||||
|
||||
handle_temperature_damage()
|
||||
|
||||
/mob/living/simple_animal/proc/handle_temperature_damage()
|
||||
if(bodytemperature < minbodytemp)
|
||||
adjustBruteLoss(cold_damage_per_tick)
|
||||
else if(bodytemperature > maxbodytemp)
|
||||
adjustBruteLoss(heat_damage_per_tick)
|
||||
if((bodytemperature < minbodytemp) || (bodytemperature > maxbodytemp))
|
||||
adjustHealth(unsuitable_atmos_damage)
|
||||
|
||||
/mob/living/simple_animal/gib()
|
||||
if(icon_gib)
|
||||
flick(icon_gib, src)
|
||||
if(butcher_results)
|
||||
var/atom/Tsec = drop_location()
|
||||
for(var/path in butcher_results)
|
||||
for(var/i = 1; i <= butcher_results[path];i++)
|
||||
new path(src.loc)
|
||||
for(var/i in 1 to butcher_results[path])
|
||||
new path(Tsec)
|
||||
..()
|
||||
|
||||
|
||||
/mob/living/simple_animal/blob_act()
|
||||
adjustBruteLoss(20)
|
||||
return
|
||||
|
||||
/mob/living/simple_animal/emote(act, m_type = 1, message = null, force)
|
||||
if(stat)
|
||||
return
|
||||
@@ -279,29 +293,13 @@
|
||||
|
||||
..()
|
||||
|
||||
/mob/living/simple_animal/bullet_act(var/obj/item/projectile/Proj)
|
||||
if(!Proj)
|
||||
return
|
||||
if((Proj.damage_type != STAMINA))
|
||||
adjustBruteLoss(Proj.damage)
|
||||
Proj.on_hit(src, 0)
|
||||
return FALSE
|
||||
/mob/living/simple_animal/say_quote(message)
|
||||
var/verb = "says"
|
||||
|
||||
/mob/living/simple_animal/attackby(obj/item/O, mob/living/user)
|
||||
if(can_collar && !collar && istype(O, /obj/item/clothing/accessory/petcollar))
|
||||
var/obj/item/clothing/accessory/petcollar/C = O
|
||||
user.drop_item()
|
||||
C.forceMove(src)
|
||||
collar = C
|
||||
collar.equipped(src)
|
||||
regenerate_icons()
|
||||
to_chat(usr, "<span class='notice'>You put \the [C] around \the [src]'s neck.</span>")
|
||||
if(C.tagname)
|
||||
name = C.tagname
|
||||
real_name = C.tagname
|
||||
return
|
||||
else
|
||||
..()
|
||||
if(speak_emote.len)
|
||||
verb = pick(speak_emote)
|
||||
|
||||
return verb
|
||||
|
||||
/mob/living/simple_animal/movement_delay()
|
||||
. = ..()
|
||||
@@ -312,21 +310,25 @@
|
||||
|
||||
/mob/living/simple_animal/Stat()
|
||||
..()
|
||||
if(statpanel("Status"))
|
||||
stat(null, "Health: [round((health / maxHealth) * 100)]%")
|
||||
return TRUE
|
||||
|
||||
statpanel("Status")
|
||||
stat(null, "Health: [round((health / maxHealth) * 100)]%")
|
||||
/mob/living/simple_animal/proc/drop_loot()
|
||||
if(loot.len)
|
||||
for(var/i in loot)
|
||||
new i(loc)
|
||||
|
||||
/mob/living/simple_animal/death(gibbed)
|
||||
// Only execute the below if we successfully died
|
||||
. = ..()
|
||||
if(!.)
|
||||
return FALSE
|
||||
flying = FALSE
|
||||
if(nest)
|
||||
nest.spawned_mobs -= src
|
||||
nest = null
|
||||
if(loot.len)
|
||||
for(var/i in loot)
|
||||
new i(loc)
|
||||
drop_loot()
|
||||
if(!gibbed)
|
||||
if(death_sound)
|
||||
playsound(get_turf(src),death_sound, 200, 1)
|
||||
@@ -335,87 +337,41 @@
|
||||
else if(!del_on_death)
|
||||
visible_message("<span class='danger'>\The [src] stops moving...</span>")
|
||||
if(del_on_death)
|
||||
//Prevent infinite loops if the mob Destroy() is overridden in such
|
||||
//a manner as to cause a call to death() again
|
||||
del_on_death = FALSE
|
||||
ghostize()
|
||||
qdel(src)
|
||||
else
|
||||
health = 0
|
||||
icon_state = icon_dead
|
||||
if(flip_on_death)
|
||||
transform = transform.Turn(180)
|
||||
density = 0
|
||||
lying = 1
|
||||
|
||||
/mob/living/simple_animal/ex_act(severity)
|
||||
..()
|
||||
switch(severity)
|
||||
if(1.0)
|
||||
gib()
|
||||
return
|
||||
|
||||
if(2.0)
|
||||
adjustBruteLoss(60)
|
||||
|
||||
|
||||
if(3.0)
|
||||
adjustBruteLoss(30)
|
||||
|
||||
/mob/living/simple_animal/proc/adjustHealth(amount, updating_health = TRUE)
|
||||
if(status_flags & GODMODE)
|
||||
return FALSE
|
||||
var/oldbruteloss = bruteloss
|
||||
bruteloss = Clamp(bruteloss + amount, 0, maxHealth)
|
||||
if(oldbruteloss == bruteloss)
|
||||
updating_health = FALSE
|
||||
. = STATUS_UPDATE_NONE
|
||||
else
|
||||
. = STATUS_UPDATE_HEALTH
|
||||
if(updating_health)
|
||||
updatehealth()
|
||||
|
||||
/mob/living/simple_animal/adjustBruteLoss(amount, updating_health = TRUE)
|
||||
if(damage_coeff[BRUTE])
|
||||
return adjustHealth(amount * damage_coeff[BRUTE], updating_health)
|
||||
|
||||
/mob/living/simple_animal/adjustFireLoss(amount, updating_health = TRUE)
|
||||
if(damage_coeff[BURN])
|
||||
return adjustHealth(amount * damage_coeff[BURN], updating_health)
|
||||
|
||||
/mob/living/simple_animal/adjustOxyLoss(amount, updating_health = TRUE)
|
||||
if(damage_coeff[OXY])
|
||||
return adjustHealth(amount * damage_coeff[OXY], updating_health)
|
||||
|
||||
/mob/living/simple_animal/adjustToxLoss(amount, updating_health = TRUE)
|
||||
if(damage_coeff[TOX])
|
||||
return adjustHealth(amount * damage_coeff[TOX], updating_health)
|
||||
|
||||
/mob/living/simple_animal/adjustCloneLoss(amount, updating_health = TRUE)
|
||||
if(damage_coeff[CLONE])
|
||||
return adjustHealth(amount * damage_coeff[CLONE], updating_health)
|
||||
|
||||
/mob/living/simple_animal/adjustStaminaLoss(amount, updating_health = TRUE)
|
||||
if(damage_coeff[STAMINA])
|
||||
return ..(amount*damage_coeff[STAMINA], updating_health)
|
||||
|
||||
/mob/living/simple_animal/proc/CanAttack(var/atom/the_target)
|
||||
/mob/living/simple_animal/proc/CanAttack(atom/the_target)
|
||||
if(see_invisible < the_target.invisibility)
|
||||
return FALSE
|
||||
if(ismob(the_target))
|
||||
var/mob/M = the_target
|
||||
if(M.status_flags & GODMODE)
|
||||
return FALSE
|
||||
if(isliving(the_target))
|
||||
var/mob/living/L = the_target
|
||||
if(L.stat != CONSCIOUS)
|
||||
return FALSE
|
||||
if(istype(the_target, /obj/mecha))
|
||||
if(ismecha(the_target))
|
||||
var/obj/mecha/M = the_target
|
||||
if(M.occupant)
|
||||
return FALSE
|
||||
if(istype(the_target,/obj/spacepod))
|
||||
if(isspacepod(the_target))
|
||||
var/obj/spacepod/S = the_target
|
||||
if(S.pilot)
|
||||
return FALSE
|
||||
return TRUE
|
||||
|
||||
/mob/living/simple_animal/handle_fire()
|
||||
return
|
||||
|
||||
/mob/living/simple_animal/update_fire()
|
||||
return
|
||||
return TRUE
|
||||
|
||||
/mob/living/simple_animal/IgniteMob()
|
||||
return FALSE
|
||||
@@ -423,32 +379,20 @@
|
||||
/mob/living/simple_animal/ExtinguishMob()
|
||||
return
|
||||
|
||||
/mob/living/simple_animal/update_transform()
|
||||
var/matrix/ntransform = matrix(transform) //aka transform.Copy()
|
||||
var/changed = 0
|
||||
|
||||
if(resize != RESIZE_DEFAULT_SIZE)
|
||||
changed++
|
||||
ntransform.Scale(resize)
|
||||
resize = RESIZE_DEFAULT_SIZE
|
||||
|
||||
if(changed)
|
||||
animate(src, transform = ntransform, time = 2, easing = EASE_IN|EASE_OUT)
|
||||
|
||||
/mob/living/simple_animal/revive()
|
||||
..()
|
||||
health = maxHealth
|
||||
icon = initial(icon)
|
||||
icon_state = icon_living
|
||||
density = initial(density)
|
||||
update_canmove()
|
||||
|
||||
|
||||
flying = initial(flying)
|
||||
|
||||
/mob/living/simple_animal/proc/make_babies() // <3 <3 <3
|
||||
if(gender != FEMALE || stat || next_scan_time > world.time || !childtype || !animal_species || !SSticker.IsRoundInProgress())
|
||||
return FALSE
|
||||
next_scan_time = world.time + 400
|
||||
|
||||
|
||||
var/alone = TRUE
|
||||
var/mob/living/simple_animal/partner
|
||||
var/children = 0
|
||||
@@ -472,42 +416,6 @@
|
||||
if(target)
|
||||
return new childspawn(target)
|
||||
|
||||
/mob/living/simple_animal/say_quote(var/message)
|
||||
var/verb = "says"
|
||||
|
||||
if(speak_emote.len)
|
||||
verb = pick(speak_emote)
|
||||
|
||||
return verb
|
||||
|
||||
/mob/living/simple_animal/update_canmove(delay_action_updates = 0)
|
||||
if(paralysis || stunned || weakened || stat || resting)
|
||||
drop_r_hand()
|
||||
drop_l_hand()
|
||||
canmove = 0
|
||||
else if(buckled)
|
||||
canmove = 0
|
||||
else
|
||||
canmove = 1
|
||||
update_transform()
|
||||
if(!delay_action_updates)
|
||||
update_action_buttons_icon()
|
||||
return canmove
|
||||
|
||||
/mob/living/simple_animal/update_transform()
|
||||
var/matrix/ntransform = matrix(transform) //aka transform.Copy()
|
||||
var/changed = 0
|
||||
|
||||
if(resize != RESIZE_DEFAULT_SIZE)
|
||||
changed++
|
||||
ntransform.Scale(resize)
|
||||
resize = RESIZE_DEFAULT_SIZE
|
||||
|
||||
if(changed)
|
||||
animate(src, transform = ntransform, time = 2, easing = EASE_IN|EASE_OUT)
|
||||
|
||||
/* Inventory */
|
||||
|
||||
/mob/living/simple_animal/show_inv(mob/user as mob)
|
||||
if(!can_collar)
|
||||
return
|
||||
@@ -572,50 +480,39 @@
|
||||
if(collar)
|
||||
. |= collar.GetAccess()
|
||||
|
||||
/* End Inventory */
|
||||
/mob/living/simple_animal/update_canmove(delay_action_updates = 0)
|
||||
if(paralysis || stunned || weakened || stat || resting)
|
||||
drop_r_hand()
|
||||
drop_l_hand()
|
||||
canmove = 0
|
||||
else if(buckled)
|
||||
canmove = 0
|
||||
else
|
||||
canmove = 1
|
||||
if(!canmove)
|
||||
walk(src, 0) //stop mid walk
|
||||
|
||||
update_transform()
|
||||
if(!delay_action_updates)
|
||||
update_action_buttons_icon()
|
||||
return canmove
|
||||
|
||||
/mob/living/simple_animal/update_transform()
|
||||
var/matrix/ntransform = matrix(transform) //aka transform.Copy()
|
||||
var/changed = FALSE
|
||||
|
||||
if(resize != RESIZE_DEFAULT_SIZE)
|
||||
changed = TRUE
|
||||
ntransform.Scale(resize)
|
||||
resize = RESIZE_DEFAULT_SIZE
|
||||
|
||||
if(changed)
|
||||
animate(src, transform = ntransform, time = 2, easing = EASE_IN|EASE_OUT)
|
||||
|
||||
/mob/living/simple_animal/proc/sentience_act() //Called when a simple animal gains sentience via gold slime potion
|
||||
toggle_ai(AI_OFF)
|
||||
can_have_ai = FALSE
|
||||
return
|
||||
|
||||
/mob/living/simple_animal/can_hear()
|
||||
. = TRUE
|
||||
|
||||
/mob/living/simple_animal/proc/consider_wakeup()
|
||||
if(pulledby || shouldwakeup)
|
||||
toggle_ai(AI_ON)
|
||||
|
||||
/mob/living/simple_animal/adjustHealth(amount, updating_health = TRUE, forced = FALSE)
|
||||
. = ..()
|
||||
if(!ckey && !stat)//Not unconscious
|
||||
if(AIStatus == AI_IDLE)
|
||||
toggle_ai(AI_ON)
|
||||
|
||||
/mob/living/simple_animal/proc/toggle_ai(togglestatus)
|
||||
if(!can_have_ai && (togglestatus != AI_OFF))
|
||||
return
|
||||
if(AIStatus != togglestatus)
|
||||
if(togglestatus > 0 && togglestatus < 5)
|
||||
if(togglestatus == AI_Z_OFF || AIStatus == AI_Z_OFF)
|
||||
var/turf/T = get_turf(src)
|
||||
if(AIStatus == AI_Z_OFF)
|
||||
SSidlenpcpool.idle_mobs_by_zlevel[T.z] -= src
|
||||
else
|
||||
SSidlenpcpool.idle_mobs_by_zlevel[T.z] += src
|
||||
GLOB.simple_animals[AIStatus] -= src
|
||||
GLOB.simple_animals[togglestatus] += src
|
||||
AIStatus = togglestatus
|
||||
else
|
||||
stack_trace("Something attempted to set simple animals AI to an invalid state: [togglestatus]")
|
||||
|
||||
/mob/living/simple_animal/onTransitZ(old_z, new_z)
|
||||
..()
|
||||
if(AIStatus == AI_Z_OFF)
|
||||
SSidlenpcpool.idle_mobs_by_zlevel[old_z] -= src
|
||||
toggle_ai(initial(AIStatus))
|
||||
|
||||
// Simple animals will not be given night vision upon death, as that would result in issues when they are revived.
|
||||
/mob/living/simple_animal/grant_death_vision()
|
||||
sight |= SEE_TURFS
|
||||
sight |= SEE_MOBS
|
||||
@@ -642,4 +539,37 @@
|
||||
return
|
||||
|
||||
SEND_SIGNAL(src, COMSIG_MOB_UPDATE_SIGHT)
|
||||
sync_lighting_plane_alpha()
|
||||
sync_lighting_plane_alpha()
|
||||
|
||||
/mob/living/simple_animal/proc/toggle_ai(togglestatus)
|
||||
if(!can_have_ai && (togglestatus != AI_OFF))
|
||||
return
|
||||
if(AIStatus != togglestatus)
|
||||
if(togglestatus > 0 && togglestatus < 5)
|
||||
if(togglestatus == AI_Z_OFF || AIStatus == AI_Z_OFF)
|
||||
var/turf/T = get_turf(src)
|
||||
if(AIStatus == AI_Z_OFF)
|
||||
SSidlenpcpool.idle_mobs_by_zlevel[T.z] -= src
|
||||
else
|
||||
SSidlenpcpool.idle_mobs_by_zlevel[T.z] += src
|
||||
GLOB.simple_animals[AIStatus] -= src
|
||||
GLOB.simple_animals[togglestatus] += src
|
||||
AIStatus = togglestatus
|
||||
else
|
||||
stack_trace("Something attempted to set simple animals AI to an invalid state: [togglestatus]")
|
||||
|
||||
/mob/living/simple_animal/proc/consider_wakeup()
|
||||
if(pulledby || shouldwakeup)
|
||||
toggle_ai(AI_ON)
|
||||
|
||||
/mob/living/simple_animal/adjustHealth(amount, updating_health = TRUE)
|
||||
. = ..()
|
||||
if(!ckey && !stat)//Not unconscious
|
||||
if(AIStatus == AI_IDLE)
|
||||
toggle_ai(AI_ON)
|
||||
|
||||
/mob/living/simple_animal/onTransitZ(old_z, new_z)
|
||||
..()
|
||||
if(AIStatus == AI_Z_OFF)
|
||||
SSidlenpcpool.idle_mobs_by_zlevel[old_z] -= src
|
||||
toggle_ai(initial(AIStatus))
|
||||
@@ -56,9 +56,6 @@
|
||||
if(abilities)
|
||||
client.verbs |= abilities
|
||||
|
||||
if(ishuman(src))
|
||||
client.screen += client.void
|
||||
|
||||
//HUD updates (antag hud, etc)
|
||||
//readd this mob's HUDs (antag, med, etc)
|
||||
reload_huds()
|
||||
|
||||
@@ -1234,12 +1234,6 @@ var/list/slot_equipment_priority = list( \
|
||||
/mob/proc/get_access()
|
||||
return list() //must return list or IGNORE_ACCESS
|
||||
|
||||
/mob/proc/faction_check(mob/target)
|
||||
for(var/F in faction)
|
||||
if(F in target.faction)
|
||||
return 1
|
||||
return 0
|
||||
|
||||
/mob/proc/create_attack_log(text, collapse = TRUE)
|
||||
LAZYINITLIST(attack_log)
|
||||
create_log_in_list(attack_log, text, collapse, last_log)
|
||||
|
||||
Binary file not shown.
|
After Width: | Height: | Size: 5.5 KiB |
Binary file not shown.
|
Before Width: | Height: | Size: 138 KiB After Width: | Height: | Size: 138 KiB |
@@ -1904,6 +1904,7 @@
|
||||
#include "code\modules\mob\living\simple_animal\animal_defense.dm"
|
||||
#include "code\modules\mob\living\simple_animal\constructs.dm"
|
||||
#include "code\modules\mob\living\simple_animal\corpse.dm"
|
||||
#include "code\modules\mob\living\simple_animal\damage_procs.dm"
|
||||
#include "code\modules\mob\living\simple_animal\parrot.dm"
|
||||
#include "code\modules\mob\living\simple_animal\posessed_object.dm"
|
||||
#include "code\modules\mob\living\simple_animal\powers.dm"
|
||||
|
||||
Reference in New Issue
Block a user