Splits jungle mobs into their own files

This commit is contained in:
Xhuis
2017-08-25 19:49:58 -04:00
parent fb134bd487
commit ce41c20170
11 changed files with 818 additions and 834 deletions

View File

@@ -0,0 +1,17 @@
/mob/living/simple_animal/hostile/jungle
vision_range = 5
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)
faction = list("jungle")
weather_immunities = list("acid")
obj_damage = 30
environment_smash = ENVIRONMENT_SMASH_WALLS
minbodytemp = 0
maxbodytemp = 450
response_help = "pokes"
response_disarm = "shoves"
response_harm = "strikes"
status_flags = 0
a_intent = INTENT_HARM
see_in_dark = 4
lighting_alpha = LIGHTING_PLANE_ALPHA_MOSTLY_INVISIBLE
mob_size = MOB_SIZE_LARGE

View File

@@ -0,0 +1,263 @@
#define PLAYER_HOP_DELAY 25
//Huge, carnivorous toads that spit an immobilizing toxin at its victims before leaping onto them.
//It has no melee attack, and its damage comes from the toxin in its bubbles and its crushing leap.
//Its eyes will turn red to signal an imminent attack!
/mob/living/simple_animal/hostile/jungle/leaper
name = "leaper"
desc = "Commonly referred to as 'leapers', the Geron Toad is a massive beast that spits out highly pressurized bubbles containing a unique toxin, knocking down its prey and then crushing it with its girth."
icon = 'icons/mob/jungle/leaper.dmi'
icon_state = "leaper"
icon_living = "leaper"
icon_dead = "leaper_dead"
maxHealth = 300
health = 300
ranged = TRUE
projectiletype = /obj/item/projectile/leaper
projectilesound = 'sound/weapons/pierce.ogg'
ranged_cooldown_time = 30
pixel_x = -16
layer = LARGE_MOB_LAYER
speed = 10
stat_attack = 1
robust_searching = 1
var/hopping = FALSE
var/hop_cooldown = 0 //Strictly for player controlled leapers
var/projectile_ready = FALSE //Stopping AI leapers from firing whenever they want, and only doing it after a hop has finished instead
/obj/item/projectile/leaper
name = "leaper bubble"
icon_state = "leaper"
knockdown = 50
damage = 0
range = 7
hitsound = 'sound/effects/snap.ogg'
nondirectional_sprite = TRUE
impact_effect_type = /obj/effect/temp_visual/leaper_projectile_impact
/obj/item/projectile/leaper/on_hit(atom/target, blocked = FALSE)
..()
if(iscarbon(target))
var/mob/living/carbon/C = target
C.reagents.add_reagent("leaper_venom", 5)
return
if(isanimal(target))
var/mob/living/simple_animal/L = target
L.adjustHealth(25)
/obj/item/projectile/leaper/on_range()
var/turf/T = get_turf(src)
..()
new /obj/structure/leaper_bubble(T)
/obj/effect/temp_visual/leaper_projectile_impact
name = "leaper bubble"
icon = 'icons/obj/projectiles.dmi'
icon_state = "leaper_bubble_pop"
layer = ABOVE_ALL_MOB_LAYER
duration = 3
/obj/effect/temp_visual/leaper_projectile_impact/Initialize()
. = ..()
new /obj/effect/decal/cleanable/leaper_sludge(get_turf(src))
/obj/effect/decal/cleanable/leaper_sludge
name = "leaper sludge"
desc = "A small pool of sludge, containing trace amounts of leaper venom."
icon = 'icons/effects/tomatodecal.dmi'
icon_state = "tomato_floor1"
/obj/structure/leaper_bubble
name = "leaper bubble"
desc = "A floating bubble containing leaper venom. The contents are under a surprising amount of pressure."
icon = 'icons/obj/projectiles.dmi'
icon_state = "leaper"
max_integrity = 10
density = FALSE
/obj/structure/leaper_bubble/Initialize()
. = ..()
float(on = TRUE)
QDEL_IN(src, 100)
/obj/structure/leaper_bubble/Destroy()
new /obj/effect/temp_visual/leaper_projectile_impact(get_turf(src))
playsound(src,'sound/effects/snap.ogg',50, 1, -1)
return ..()
/obj/structure/leaper_bubble/Crossed(atom/movable/AM)
if(isliving(AM))
var/mob/living/L = AM
if(!istype(L, /mob/living/simple_animal/hostile/jungle/leaper))
playsound(src,'sound/effects/snap.ogg',50, 1, -1)
L.Knockdown(50)
if(iscarbon(L))
var/mob/living/carbon/C = L
C.reagents.add_reagent("leaper_venom", 5)
if(isanimal(L))
var/mob/living/simple_animal/A = L
A.adjustHealth(25)
qdel(src)
return ..()
/datum/reagent/toxin/leaper_venom
name = "Leaper venom"
id = "leaper_venom"
description = "A toxin spat out by leapers that, while harmless in small doses, quickly creates a toxic reaction if too much is in the body."
color = "#801E28" // rgb: 128, 30, 40
toxpwr = 0
taste_description = "french cuisine"
taste_mult = 1.3
/datum/reagent/toxin/leaper_venom/on_mob_life(mob/living/M)
if(volume >= 10)
M.adjustToxLoss(5, 0)
..()
/obj/effect/temp_visual/leaper_crush
name = "grim tidings"
desc = "Incoming leaper!"
icon = 'icons/effects/96x96.dmi'
icon_state = "lily_pad"
layer = BELOW_MOB_LAYER
pixel_x = -32
pixel_y = -32
duration = 30
/mob/living/simple_animal/hostile/jungle/leaper/Initialize()
. = ..()
verbs -= /mob/living/verb/pulled
/mob/living/simple_animal/hostile/jungle/leaper/CtrlClickOn(atom/A)
face_atom(A)
target = A
if(!isturf(loc))
return
if(next_move > world.time)
return
if(hopping)
return
if(isliving(A))
var/mob/living/L = A
if(L.incapacitated())
BellyFlop()
return
if(hop_cooldown <= world.time)
Hop(player_hop = TRUE)
/mob/living/simple_animal/hostile/jungle/leaper/AttackingTarget()
if(isliving(target))
return
return ..()
/mob/living/simple_animal/hostile/jungle/leaper/handle_automated_action()
if(hopping || projectile_ready)
return
. = ..()
if(target)
if(isliving(target))
var/mob/living/L = target
if(L.incapacitated())
BellyFlop()
return
if(!hopping)
Hop()
/mob/living/simple_animal/hostile/jungle/leaper/Life()
. = ..()
update_icons()
/mob/living/simple_animal/hostile/jungle/leaper/adjustHealth(amount, updating_health = TRUE, forced = FALSE)
if(prob(33) && !ckey)
ranged_cooldown = 0 //Keeps em on their toes instead of a constant rotation
..()
/mob/living/simple_animal/hostile/jungle/leaper/OpenFire()
face_atom(target)
if(ranged_cooldown <= world.time)
if(ckey)
if(hopping)
return
if(isliving(target))
var/mob/living/L = target
if(L.incapacitated())
return //No stunlocking. Hop on them after you stun them, you donk.
if(AIStatus == AI_ON && !projectile_ready && !ckey)
return
. = ..(target)
projectile_ready = FALSE
update_icons()
/mob/living/simple_animal/hostile/jungle/leaper/proc/Hop(player_hop = FALSE)
if(z != target.z)
return
hopping = TRUE
density = FALSE
pass_flags |= PASSMOB
notransform = TRUE
var/turf/new_turf = locate((target.x + rand(-3,3)),(target.y + rand(-3,3)),target.z)
if(player_hop)
new_turf = get_turf(target)
hop_cooldown = world.time + PLAYER_HOP_DELAY
if(AIStatus == AI_ON && ranged_cooldown <= world.time)
projectile_ready = TRUE
update_icons()
throw_at(new_turf, max(3,get_dist(src,new_turf)), 1, src, FALSE, callback = CALLBACK(src, .FinishHop))
/mob/living/simple_animal/hostile/jungle/leaper/proc/FinishHop()
density = TRUE
notransform = FALSE
pass_flags &= ~PASSMOB
hopping = FALSE
playsound(src.loc, 'sound/effects/meteorimpact.ogg', 100, 1)
if(target && AIStatus == AI_ON && projectile_ready && !ckey)
face_atom(target)
addtimer(CALLBACK(src, .proc/OpenFire, target), 5)
/mob/living/simple_animal/hostile/jungle/leaper/proc/BellyFlop()
var/turf/new_turf = get_turf(target)
hopping = TRUE
notransform = TRUE
new /obj/effect/temp_visual/leaper_crush(new_turf)
addtimer(CALLBACK(src, .proc/BellyFlopHop, new_turf), 30)
/mob/living/simple_animal/hostile/jungle/leaper/proc/BellyFlopHop(turf/T)
density = FALSE
throw_at(T, get_dist(src,T),1,src, FALSE, callback = CALLBACK(src, .proc/Crush))
/mob/living/simple_animal/hostile/jungle/leaper/proc/Crush()
hopping = FALSE
density = TRUE
notransform = FALSE
playsound(src, 'sound/effects/meteorimpact.ogg', 200, 1)
for(var/mob/living/L in orange(1, src))
L.adjustBruteLoss(35)
if(!QDELETED(L)) // Some mobs are deleted on death
var/throw_dir = get_dir(src, L)
if(L.loc == loc)
throw_dir = pick(GLOB.alldirs)
var/throwtarget = get_edge_target_turf(src, throw_dir)
L.throw_at(throwtarget, 3, 1)
visible_message("<span class='warning'>[L] is thrown clear of [src]!</span>")
if(ckey)//Lessens ability to chain stun as a player
ranged_cooldown = ranged_cooldown_time + world.time
update_icons()
/mob/living/simple_animal/hostile/jungle/leaper/Goto()
return
/mob/living/simple_animal/hostile/jungle/leaper/throw_impact()
return
/mob/living/simple_animal/hostile/jungle/leaper/update_icons()
. = ..()
if(stat)
icon_state = "leaper_dead"
return
if(ranged_cooldown <= world.time)
if(AIStatus == AI_ON && projectile_ready || ckey)
icon_state = "leaper_alert"
return
icon_state = "leaper"
#undef PLAYER_HOP_DELAY

View File

@@ -0,0 +1,65 @@
//Large and powerful, but timid. It won't engage anything above 50 health, or anything without legcuffs.
//It can fire fleshy snares that legcuff anyone that it hits, making them look especially tasty to the arachnid.
/mob/living/simple_animal/hostile/jungle/mega_arachnid
name = "mega arachnid"
desc = "Though physically imposing, it prefers to ambush its prey, and it will only engage with an already crippled opponent."
icon = 'icons/mob/jungle/arachnid.dmi'
icon_state = "arachnid"
icon_living = "arachnid"
icon_dead = "arachnid_dead"
melee_damage_lower = 30
melee_damage_upper = 30
maxHealth = 300
health = 300
speed = 1
ranged = 1
pixel_x = -16
move_to_delay = 10
aggro_vision_range = 9
speak_emote = list("chitters")
attack_sound = 'sound/weapons/bladeslice.ogg'
ranged_cooldown_time = 60
projectiletype = /obj/item/projectile/mega_arachnid
projectilesound = 'sound/weapons/pierce.ogg'
alpha = 50
/mob/living/simple_animal/hostile/jungle/mega_arachnid/Life()
..()
if(target && ranged_cooldown > world.time && iscarbon(target))
var/mob/living/carbon/C = target
if(!C.legcuffed && C.health < 50)
retreat_distance = 9
minimum_distance = 9
alpha = 125
return
retreat_distance = 0
minimum_distance = 0
alpha = 255
/mob/living/simple_animal/hostile/jungle/mega_arachnid/Aggro()
..()
alpha = 255
/mob/living/simple_animal/hostile/jungle/mega_arachnid/LoseAggro()
..()
alpha = 50
/obj/item/projectile/mega_arachnid
name = "flesh snare"
nodamage = 1
damage = 0
icon_state = "tentacle_end"
/obj/item/projectile/mega_arachnid/on_hit(atom/target, blocked = FALSE)
if(iscarbon(target) && blocked < 100)
var/obj/item/restraints/legcuffs/beartrap/mega_arachnid/B = new /obj/item/restraints/legcuffs/beartrap/mega_arachnid(get_turf(target))
B.Crossed(target)
..()
/obj/item/restraints/legcuffs/beartrap/mega_arachnid
name = "fleshy restraints"
desc = "Used by mega arachnids to immobilize their prey."
flags_1 = DROPDEL_1
icon_state = "tentacle_end"
icon = 'icons/obj/projectiles.dmi'

View File

@@ -0,0 +1,224 @@
#define MOOK_ATTACK_NEUTRAL 0
#define MOOK_ATTACK_WARMUP 1
#define MOOK_ATTACK_ACTIVE 2
#define MOOK_ATTACK_RECOVERY 3
#define ATTACK_INTERMISSION_TIME 5
//Fragile but highly aggressive wanderers that pose a large threat in numbers.
//They'll attempt to leap at their target from afar using their hatchets.
/mob/living/simple_animal/hostile/jungle/mook
name = "wanderer"
desc = "This unhealthy looking primitive is wielding a rudimentary hatchet, swinging it with wild abandon. One isn't much of a threat, but in numbers they can quickly overwhelm a superior opponent."
icon = 'icons/mob/jungle/mook.dmi'
icon_state = "mook"
icon_living = "mook"
icon_dead = "mook_dead"
pixel_x = -16
maxHealth = 45
health = 45
melee_damage_lower = 30
melee_damage_upper = 30
pixel_y = -8
ranged = TRUE
ranged_cooldown_time = 10
pass_flags = LETPASSTHROW
robust_searching = TRUE
stat_attack = UNCONSCIOUS
attack_sound = 'sound/weapons/rapierhit.ogg'
death_sound = 'sound/voice/mook_death.ogg'
aggro_vision_range = 15 //A little more aggressive once in combat to balance out their really low HP
var/attack_state = MOOK_ATTACK_NEUTRAL
var/struck_target_leap = FALSE
/mob/living/simple_animal/hostile/jungle/mook/CanPass(atom/movable/O)
if(istype(O, /mob/living/simple_animal/hostile/jungle/mook))
var/mob/living/simple_animal/hostile/jungle/mook/M = O
if(M.attack_state == MOOK_ATTACK_ACTIVE && M.throwing)
return TRUE
return ..()
/mob/living/simple_animal/hostile/jungle/mook/death()
desc = "A deceased primitive. Upon closer inspection, it was suffering from severe cellular degeneration and its garments are machine made..."//Can you guess the twist
return ..()
/mob/living/simple_animal/hostile/jungle/mook/AttackingTarget()
if(isliving(target))
if(ranged_cooldown <= world.time && attack_state == MOOK_ATTACK_NEUTRAL)
var/mob/living/L = target
if(L.incapacitated())
WarmupAttack(forced_slash_combo = TRUE)
return
WarmupAttack()
return
return ..()
/mob/living/simple_animal/hostile/jungle/mook/Goto()
if(attack_state != MOOK_ATTACK_NEUTRAL)
return
return ..()
/mob/living/simple_animal/hostile/jungle/mook/Move()
if(attack_state == MOOK_ATTACK_WARMUP || attack_state == MOOK_ATTACK_RECOVERY)
return
return ..()
/mob/living/simple_animal/hostile/jungle/mook/proc/WarmupAttack(forced_slash_combo = FALSE)
if(attack_state == MOOK_ATTACK_NEUTRAL && target)
attack_state = MOOK_ATTACK_WARMUP
walk(src,0)
update_icons()
if(prob(50) && get_dist(src,target) <= 3 || forced_slash_combo)
addtimer(CALLBACK(src, .proc/SlashCombo), ATTACK_INTERMISSION_TIME)
return
addtimer(CALLBACK(src, .proc/LeapAttack), ATTACK_INTERMISSION_TIME + rand(0,3))
return
attack_state = MOOK_ATTACK_RECOVERY
ResetNeutral()
/mob/living/simple_animal/hostile/jungle/mook/proc/SlashCombo()
if(attack_state == MOOK_ATTACK_WARMUP && !stat)
attack_state = MOOK_ATTACK_ACTIVE
update_icons()
SlashAttack()
addtimer(CALLBACK(src, .proc/SlashAttack), 3)
addtimer(CALLBACK(src, .proc/SlashAttack), 6)
addtimer(CALLBACK(src, .proc/AttackRecovery), 9)
/mob/living/simple_animal/hostile/jungle/mook/proc/SlashAttack()
if(target && !stat && attack_state == MOOK_ATTACK_ACTIVE)
melee_damage_lower = 15
melee_damage_upper = 15
var/mob_direction = get_dir(src,target)
if(get_dist(src,target) > 1)
step(src,mob_direction)
if(targets_from && isturf(targets_from.loc) && target.Adjacent(targets_from) && isliving(target))
var/mob/living/L = target
L.attack_animal(src)
return
var/swing_turf = get_step(src,mob_direction)
new /obj/effect/temp_visual/kinetic_blast(swing_turf)
playsound(src, 'sound/weapons/slashmiss.ogg', 50, 1)
/mob/living/simple_animal/hostile/jungle/mook/proc/LeapAttack()
if(target && !stat && attack_state == MOOK_ATTACK_WARMUP)
attack_state = MOOK_ATTACK_ACTIVE
density = FALSE
melee_damage_lower = 30
melee_damage_upper = 30
update_icons()
new /obj/effect/temp_visual/mook_dust(get_turf(src))
playsound(src, 'sound/weapons/thudswoosh.ogg', 25, 1)
playsound(src, 'sound/voice/mook_leap_yell.ogg', 100, 1)
var/target_turf = get_turf(target)
throw_at(target_turf, 7, 1, src, FALSE, callback = CALLBACK(src, .proc/AttackRecovery))
return
attack_state = MOOK_ATTACK_RECOVERY
ResetNeutral()
/mob/living/simple_animal/hostile/jungle/mook/proc/AttackRecovery()
if(attack_state == MOOK_ATTACK_ACTIVE && !stat)
attack_state = MOOK_ATTACK_RECOVERY
density = TRUE
face_atom(target)
if(!struck_target_leap)
update_icons()
struck_target_leap = FALSE
if(prob(40))
attack_state = MOOK_ATTACK_NEUTRAL
if(target)
if(isliving(target))
var/mob/living/L = target
if(L.incapacitated() && L.stat != DEAD)
addtimer(CALLBACK(src, .proc/WarmupAttack, TRUE), ATTACK_INTERMISSION_TIME)
return
addtimer(CALLBACK(src, .proc/WarmupAttack), ATTACK_INTERMISSION_TIME)
return
addtimer(CALLBACK(src, .proc/ResetNeutral), ATTACK_INTERMISSION_TIME)
/mob/living/simple_animal/hostile/jungle/mook/proc/ResetNeutral()
if(attack_state == MOOK_ATTACK_RECOVERY)
attack_state = MOOK_ATTACK_NEUTRAL
ranged_cooldown = world.time + ranged_cooldown_time
update_icons()
if(target && !stat)
update_icons()
Goto(target, move_to_delay, minimum_distance)
/mob/living/simple_animal/hostile/jungle/mook/throw_impact(atom/hit_atom, throwingdatum)
. = ..()
if(isliving(hit_atom) && attack_state == MOOK_ATTACK_ACTIVE)
var/mob/living/L = hit_atom
if(CanAttack(L))
L.attack_animal(src)
struck_target_leap = TRUE
density = TRUE
update_icons()
var/mook_under_us = FALSE
for(var/A in get_turf(src))
if(struck_target_leap && mook_under_us)
break
if(A == src)
continue
if(isliving(A))
var/mob/living/ML = A
if(!struck_target_leap && CanAttack(ML))//Check if some joker is attempting to use rest to evade us
struck_target_leap = TRUE
ML.attack_animal(src)
density = TRUE
struck_target_leap = TRUE
update_icons()
continue
if(istype(ML, /mob/living/simple_animal/hostile/jungle/mook) && !mook_under_us)//If we land on the same tile as another mook, spread out so we don't stack our sprite on the same tile
var/mob/living/simple_animal/hostile/jungle/mook/M = ML
if(!M.stat)
mook_under_us = TRUE
var/anydir = pick(GLOB.cardinals)
Move(get_step(src, anydir), anydir)
continue
/mob/living/simple_animal/hostile/jungle/mook/handle_automated_action()
if(attack_state)
return
return ..()
/mob/living/simple_animal/hostile/jungle/mook/OpenFire()
if(isliving(target))
var/mob/living/L = target
if(L.incapacitated())
return
WarmupAttack()
/mob/living/simple_animal/hostile/jungle/mook/update_icons()
. = ..()
if(!stat)
switch(attack_state)
if(MOOK_ATTACK_NEUTRAL)
icon_state = "mook"
if(MOOK_ATTACK_WARMUP)
icon_state = "mook_warmup"
if(MOOK_ATTACK_ACTIVE)
if(!density)
icon_state = "mook_leap"
return
if(struck_target_leap)
icon_state = "mook_strike"
return
icon_state = "mook_slash_combo"
if(MOOK_ATTACK_RECOVERY)
icon_state = "mook"
/obj/effect/temp_visual/mook_dust
name = "dust"
desc = "it's just a dust cloud!"
icon = 'icons/mob/jungle/mook.dmi'
icon_state = "mook_leap_cloud"
layer = BELOW_MOB_LAYER
pixel_x = -16
pixel_y = -16
duration = 10
#undef MOOK_ATTACK_NEUTRAL
#undef MOOK_ATTACK_WARMUP
#undef MOOK_ATTACK_ACTIVE
#undef MOOK_ATTACK_RECOVERY
#undef ATTACK_INTERMISSION_TIME

View File

@@ -0,0 +1,244 @@
#define SEEDLING_STATE_NEUTRAL 0
#define SEEDLING_STATE_WARMUP 1
#define SEEDLING_STATE_ACTIVE 2
#define SEEDLING_STATE_RECOVERY 3
//A plant rooted in the ground that forfeits its melee attack in favor of ranged barrages.
//It will fire flurries of solar energy, and occasionally charge up a powerful blast that makes it vulnerable to attack.
/mob/living/simple_animal/hostile/jungle/seedling
name = "seedling"
desc = "This oversized, predatory flower conceals what can only be described as an organic energy cannon, and it will not die until its hidden vital organs are sliced out. \
The concentrated streams of energy it sometimes produces require its full attention, attacking it during this time will prevent it from finishing its attack."
icon = 'icons/mob/jungle/seedling.dmi'
icon_state = "seedling"
icon_living = "seedling"
icon_dead = "seedling_dead"
maxHealth = 100
health = 100
melee_damage_lower = 30
melee_damage_upper = 30
pixel_x = -16
pixel_y = -14
minimum_distance = 3
move_to_delay = 20
vision_range = 9
aggro_vision_range = 15
ranged = TRUE
ranged_cooldown_time = 10
projectiletype = /obj/item/projectile/seedling
projectilesound = 'sound/weapons/pierce.ogg'
robust_searching = TRUE
stat_attack = UNCONSCIOUS
anchored = TRUE
var/combatant_state = SEEDLING_STATE_NEUTRAL
var/obj/seedling_weakpoint/weak_point
var/mob/living/beam_debuff_target
var/solar_beam_identifier = 0
/obj/item/projectile/seedling
name = "solar energy"
icon_state = "seedling"
damage = 10
damage_type = BURN
light_range = 2
flag = "energy"
light_color = LIGHT_COLOR_YELLOW
hitsound = 'sound/weapons/sear.ogg'
hitsound_wall = 'sound/weapons/effects/searwall.ogg'
nondirectional_sprite = TRUE
/obj/item/projectile/seedling/Collide(atom/A)//Stops seedlings from destroying other jungle mobs through FF
if(isliving(A))
var/mob/living/L = A
if("jungle" in L.faction)
return FALSE
return ..()
/obj/effect/temp_visual/solarbeam_killsat
name = "beam of solar energy"
icon_state = "solar_beam"
icon = 'icons/effects/beam.dmi'
layer = LIGHTING_LAYER
duration = 5
randomdir = FALSE
/datum/status_effect/seedling_beam_indicator
id = "seedling beam indicator"
duration = 30
status_type = STATUS_EFFECT_MULTIPLE
alert_type = null
tick_interval = 1
var/obj/screen/seedling/seedling_screen_object
var/atom/target
/datum/status_effect/seedling_beam_indicator/on_creation(mob/living/new_owner, target_plant)
. = ..()
if(.)
target = target_plant
tick()
/datum/status_effect/seedling_beam_indicator/on_apply()
if(owner.client)
seedling_screen_object = new /obj/screen/seedling()
owner.client.screen += seedling_screen_object
tick()
return ..()
/datum/status_effect/seedling_beam_indicator/Destroy()
if(owner)
if(owner.client)
owner.client.screen -= seedling_screen_object
return ..()
/datum/status_effect/seedling_beam_indicator/tick()
var/target_angle = Get_Angle(owner, target)
var/matrix/final = matrix()
final.Turn(target_angle)
seedling_screen_object.transform = final
/obj/screen/seedling
icon = 'icons/mob/jungle/arachnid.dmi'
icon_state = "seedling_beam_indicator"
screen_loc = "CENTER:-16,CENTER:-16"
/mob/living/simple_animal/hostile/jungle/seedling/Goto()
if(combatant_state != SEEDLING_STATE_NEUTRAL)
return
return ..()
/mob/living/simple_animal/hostile/jungle/seedling/AttackingTarget()
if(isliving(target))
if(ranged_cooldown <= world.time && combatant_state == SEEDLING_STATE_NEUTRAL)
OpenFire(target)
return
return ..()
/mob/living/simple_animal/hostile/jungle/seedling/OpenFire()
WarmupAttack()
/mob/living/simple_animal/hostile/jungle/seedling/proc/WarmupAttack()
if(combatant_state == SEEDLING_STATE_NEUTRAL)
combatant_state = SEEDLING_STATE_WARMUP
walk(src,0)
update_icons()
var/target_dist = get_dist(src,target)
var/living_target_check = isliving(target)
if(living_target_check)
if(target_dist > 7)//Offscreen check
SolarBeamStartup(target)
return
if(get_dist(src,target) >= 4 && prob(40))
SolarBeamStartup(target)
return
addtimer(CALLBACK(src, .proc/Volley), 5)
/mob/living/simple_animal/hostile/jungle/seedling/proc/SolarBeamStartup(mob/living/living_target)//It's more like requiem than final spark
if(combatant_state == SEEDLING_STATE_WARMUP && target)
combatant_state = SEEDLING_STATE_ACTIVE
living_target.apply_status_effect(/datum/status_effect/seedling_beam_indicator, src)
beam_debuff_target = living_target
playsound(src,'sound/effects/seedling_chargeup.ogg', 100, 0)
if(get_dist(src,living_target) > 7)
playsound(living_target,'sound/effects/seedling_chargeup.ogg', 100, 0)
solar_beam_identifier = world.time
addtimer(CALLBACK(src, .proc/Beamu, living_target, solar_beam_identifier), 35)
/mob/living/simple_animal/hostile/jungle/seedling/proc/Beamu(mob/living/living_target, beam_id = 0)
if(combatant_state == SEEDLING_STATE_ACTIVE && living_target && beam_id == solar_beam_identifier)
if(living_target.z == z)
update_icons()
var/obj/effect/temp_visual/solarbeam_killsat/S = new (get_turf(src))
var/matrix/starting = matrix()
starting.Scale(1,32)
starting.Translate(0,520)
S.transform = starting
var/obj/effect/temp_visual/solarbeam_killsat/K = new (get_turf(living_target))
var/matrix/final = matrix()
final.Scale(1,32)
final.Translate(0,512)
K.transform = final
living_target.adjustFireLoss(30)
living_target.adjust_fire_stacks(0.2)//Just here for the showmanship
living_target.IgniteMob()
playsound(living_target,'sound/weapons/sear.ogg', 50, 1)
addtimer(CALLBACK(src, .proc/AttackRecovery), 5)
return
AttackRecovery()
/mob/living/simple_animal/hostile/jungle/seedling/proc/Volley()
if(combatant_state == SEEDLING_STATE_WARMUP && target)
combatant_state = SEEDLING_STATE_ACTIVE
update_icons()
var/datum/callback/cb = CALLBACK(src, .proc/InaccurateShot)
for(var/i in 1 to 13)
addtimer(cb, i)
addtimer(CALLBACK(src, .proc/AttackRecovery), 14)
/mob/living/simple_animal/hostile/jungle/seedling/proc/InaccurateShot()
if(!QDELETED(target) && combatant_state == SEEDLING_STATE_ACTIVE && !stat)
if(get_dist(src,target) <= 3)//If they're close enough just aim straight at them so we don't miss at point blank ranges
Shoot(target)
return
var/turf/our_turf = get_turf(src)
var/obj/item/projectile/seedling/readied_shot = new /obj/item/projectile/seedling(our_turf)
readied_shot.current = our_turf
readied_shot.starting = our_turf
readied_shot.firer = src
readied_shot.original = target
readied_shot.yo = target.y - our_turf.y + rand(-1,1)
readied_shot.xo = target.x - our_turf.x + rand(-1,1)
readied_shot.fire()
playsound(src, projectilesound, 100, 1)
/mob/living/simple_animal/hostile/jungle/seedling/proc/AttackRecovery()
if(combatant_state == SEEDLING_STATE_ACTIVE)
combatant_state = SEEDLING_STATE_RECOVERY
update_icons()
ranged_cooldown = world.time + ranged_cooldown_time
if(target)
face_atom(target)
addtimer(CALLBACK(src, .proc/ResetNeutral), 10)
/mob/living/simple_animal/hostile/jungle/seedling/proc/ResetNeutral()
combatant_state = SEEDLING_STATE_NEUTRAL
if(target && !stat)
update_icons()
Goto(target, move_to_delay, minimum_distance)
/mob/living/simple_animal/hostile/jungle/seedling/adjustHealth()
. = ..()
if(combatant_state == SEEDLING_STATE_ACTIVE && beam_debuff_target)
beam_debuff_target.remove_status_effect(/datum/status_effect/seedling_beam_indicator)
beam_debuff_target = null
solar_beam_identifier = 0
AttackRecovery()
/mob/living/simple_animal/hostile/jungle/seedling/update_icons()
. = ..()
if(!stat)
switch(combatant_state)
if(SEEDLING_STATE_NEUTRAL)
icon_state = "seedling"
if(SEEDLING_STATE_WARMUP)
icon_state = "seedling_charging"
if(SEEDLING_STATE_ACTIVE)
icon_state = "seedling_fire"
if(SEEDLING_STATE_RECOVERY)
icon_state = "seedling"
/mob/living/simple_animal/hostile/jungle/seedling/GiveTarget()
if(target)
if(combatant_state == SEEDLING_STATE_WARMUP || combatant_state == SEEDLING_STATE_ACTIVE)//So it doesn't 180 and blast you in the face while it's firing at someone else
return
return ..()
/mob/living/simple_animal/hostile/jungle/seedling/LoseTarget()
if(combatant_state == SEEDLING_STATE_WARMUP || combatant_state == SEEDLING_STATE_ACTIVE)
return
return ..()
#undef SEEDLING_STATE_NEUTRAL
#undef SEEDLING_STATE_WARMUP
#undef SEEDLING_STATE_ACTIVE
#undef SEEDLING_STATE_RECOVERY

View File

@@ -1,833 +0,0 @@
/mob/living/simple_animal/hostile/jungle
vision_range = 5
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)
faction = list("jungle")
weather_immunities = list("acid")
obj_damage = 30
environment_smash = ENVIRONMENT_SMASH_WALLS
minbodytemp = 0
maxbodytemp = 450
response_help = "pokes"
response_disarm = "shoves"
response_harm = "strikes"
status_flags = 0
a_intent = INTENT_HARM
see_in_dark = 4
lighting_alpha = LIGHTING_PLANE_ALPHA_MOSTLY_INVISIBLE
mob_size = MOB_SIZE_LARGE
//Mega arachnid
/mob/living/simple_animal/hostile/jungle/mega_arachnid
name = "mega arachnid"
desc = "Though physically imposing, it prefers to ambush its prey, and it will only engage with an already crippled opponent."
melee_damage_lower = 30
melee_damage_upper = 30
maxHealth = 300
health = 300
speed = 1
ranged = 1
pixel_x = -16
move_to_delay = 10
aggro_vision_range = 9
speak_emote = list("chitters")
attack_sound = 'sound/weapons/bladeslice.ogg'
ranged_cooldown_time = 60
projectiletype = /obj/item/projectile/mega_arachnid
projectilesound = 'sound/weapons/pierce.ogg'
icon = 'icons/mob/jungle/arachnid.dmi'
icon_state = "arachnid"
icon_living = "arachnid"
icon_dead = "dead_purple"
alpha = 50
/mob/living/simple_animal/hostile/jungle/mega_arachnid/Life()
..()
if(target && ranged_cooldown > world.time && iscarbon(target))
var/mob/living/carbon/C = target
if(!C.legcuffed && C.health < 50)
retreat_distance = 9
minimum_distance = 9
alpha = 125
return
retreat_distance = 0
minimum_distance = 0
alpha = 255
/mob/living/simple_animal/hostile/jungle/mega_arachnid/Aggro()
..()
alpha = 255
/mob/living/simple_animal/hostile/jungle/mega_arachnid/LoseAggro()
..()
alpha = 50
/obj/item/projectile/mega_arachnid
name = "flesh snare"
nodamage = 1
damage = 0
icon_state = "tentacle_end"
/obj/item/projectile/mega_arachnid/on_hit(atom/target, blocked = FALSE)
if(iscarbon(target) && blocked < 100)
var/obj/item/restraints/legcuffs/beartrap/mega_arachnid/B = new /obj/item/restraints/legcuffs/beartrap/mega_arachnid(get_turf(target))
B.Crossed(target)
..()
/obj/item/restraints/legcuffs/beartrap/mega_arachnid
name = "fleshy restraints"
desc = "Used by mega arachnids to immobilize their prey."
flags_1 = DROPDEL_1
icon_state = "tentacle_end"
icon = 'icons/obj/projectiles.dmi'
////Leaper////
#define PLAYER_HOP_DELAY 25
/mob/living/simple_animal/hostile/jungle/leaper
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)
faction = list("jungle")
weather_immunities = list("acid")
obj_damage = 30
environment_smash = ENVIRONMENT_SMASH_WALLS
maxHealth = 300
health = 300
minbodytemp = 0
maxbodytemp = 450
response_help = "pokes"
response_disarm = "shoves"
response_harm = "strikes"
status_flags = 0
a_intent = INTENT_HARM
see_in_dark = 4
ranged = TRUE
projectiletype = /obj/item/projectile/leaper
projectilesound = 'sound/weapons/pierce.ogg'
ranged_cooldown_time = 30
pixel_x = -16
icon = 'icons/mob/jungle/arachnid.dmi'
icon_state = "leaper"
icon_living = "leaper"
icon_dead = "leaper_dead"
layer = LARGE_MOB_LAYER
name = "leaper"
desc = "Commonly referred to as 'leapers', the Geron Toad is a massive beast that spits out highly pressurized bubbles containing a unique toxin, knocking down its prey and then crushing it with its girth."
speed = 10
stat_attack = 1
robust_searching = 1
var/hopping = FALSE
var/hop_cooldown = 0 //Strictly for player controlled leapers
var/projectile_ready = FALSE //Stopping AI leapers from firing whenever they want, and only doing it after a hop has finished instead
/obj/item/projectile/leaper
name = "leaper bubble"
icon_state = "leaper"
knockdown = 50
damage = 0
range = 7
hitsound = 'sound/effects/snap.ogg'
nondirectional_sprite = TRUE
impact_effect_type = /obj/effect/temp_visual/leaper_projectile_impact
/obj/item/projectile/leaper/on_hit(atom/target, blocked = FALSE)
..()
if(iscarbon(target))
var/mob/living/carbon/C = target
C.reagents.add_reagent("leaper_venom", 5)
return
if(isanimal(target))
var/mob/living/simple_animal/L = target
L.adjustHealth(25)
/obj/item/projectile/leaper/on_range()
var/turf/T = get_turf(src)
..()
new /obj/structure/leaper_bubble(T)
/obj/effect/temp_visual/leaper_projectile_impact
name = "leaper bubble"
icon = 'icons/obj/projectiles.dmi'
icon_state = "leaper_bubble_pop"
layer = ABOVE_ALL_MOB_LAYER
duration = 3
/obj/effect/temp_visual/leaper_projectile_impact/Initialize()
. = ..()
new /obj/effect/decal/cleanable/leaper_sludge(get_turf(src))
/obj/effect/decal/cleanable/leaper_sludge
name = "leaper sludge"
desc = "A small pool of sludge, containing trace amounts of leaper venom"
icon = 'icons/effects/tomatodecal.dmi'
icon_state = "tomato_floor1"
/obj/structure/leaper_bubble
name = "leaper bubble"
desc = "A floating bubble containing leaper venom, the contents are under a surprising amount of pressure."
icon = 'icons/obj/projectiles.dmi'
icon_state = "leaper"
max_integrity = 10
density = FALSE
/obj/structure/leaper_bubble/Initialize()
. = ..()
float(on = TRUE)
QDEL_IN(src, 100)
/obj/structure/leaper_bubble/Destroy()
new /obj/effect/temp_visual/leaper_projectile_impact(get_turf(src))
playsound(src,'sound/effects/snap.ogg',50, 1, -1)
return ..()
/obj/structure/leaper_bubble/Crossed(atom/movable/AM)
if(isliving(AM))
var/mob/living/L = AM
if(!istype(L, /mob/living/simple_animal/hostile/jungle/leaper))
playsound(src,'sound/effects/snap.ogg',50, 1, -1)
L.Knockdown(50)
if(iscarbon(L))
var/mob/living/carbon/C = L
C.reagents.add_reagent("leaper_venom", 5)
if(isanimal(L))
var/mob/living/simple_animal/A = L
A.adjustHealth(25)
qdel(src)
return ..()
/datum/reagent/toxin/leaper_venom
name = "Leaper venom"
id = "leaper_venom"
description = "A toxin spat out by leapers that while harmless in small doses, quickly creates a toxic reaction if too much is in the body."
color = "#801E28" // rgb: 128, 30, 40
toxpwr = 0
taste_description = "french cuisine"
taste_mult = 1.3
/datum/reagent/toxin/leaper_venom/on_mob_life(mob/living/M)
if(volume >= 10)
M.adjustToxLoss(5, 0)
..()
/obj/effect/temp_visual/leaper_crush
name = "Grim tidings"
desc = "Incoming leaper!"
icon = 'icons/effects/96x96.dmi'
icon_state = "lily_pad"
layer = BELOW_MOB_LAYER
pixel_x = -32
pixel_y = -32
duration = 30
/mob/living/simple_animal/hostile/jungle/leaper/Initialize()
. = ..()
verbs -= /mob/living/verb/pulled
/mob/living/simple_animal/hostile/jungle/leaper/CtrlClickOn(atom/A)
face_atom(A)
target = A
if(!isturf(loc))
return
if(next_move > world.time)
return
if(hopping)
return
if(isliving(A))
var/mob/living/L = A
if(L.incapacitated())
BellyFlop()
return
if(hop_cooldown <= world.time)
Hop(player_hop = TRUE)
/mob/living/simple_animal/hostile/jungle/leaper/AttackingTarget()
if(isliving(target))
return
return ..()
/mob/living/simple_animal/hostile/jungle/leaper/handle_automated_action()
if(hopping || projectile_ready)
return
. = ..()
if(target)
if(isliving(target))
var/mob/living/L = target
if(L.incapacitated())
BellyFlop()
return
if(!hopping)
Hop()
/mob/living/simple_animal/hostile/jungle/leaper/Life()
. = ..()
update_icons()
/mob/living/simple_animal/hostile/jungle/leaper/adjustHealth(amount, updating_health = TRUE, forced = FALSE)
if(prob(33) && !ckey)
ranged_cooldown = 0 //Keeps em on their toes instead of a constant rotation
..()
/mob/living/simple_animal/hostile/jungle/leaper/OpenFire()
face_atom(target)
if(ranged_cooldown <= world.time)
if(ckey)
if(hopping)
return
if(isliving(target))
var/mob/living/L = target
if(L.incapacitated())
return //No stunlocking. Hop on them after you stun them, you donk.
if(AIStatus == AI_ON && !projectile_ready && !ckey)
return
. = ..(target)
projectile_ready = FALSE
update_icons()
/mob/living/simple_animal/hostile/jungle/leaper/proc/Hop(player_hop = FALSE)
if(z != target.z)
return
hopping = TRUE
density = FALSE
pass_flags |= PASSMOB
notransform = TRUE
var/turf/new_turf = locate((target.x + rand(-3,3)),(target.y + rand(-3,3)),target.z)
if(player_hop)
new_turf = get_turf(target)
hop_cooldown = world.time + PLAYER_HOP_DELAY
if(AIStatus == AI_ON && ranged_cooldown <= world.time)
projectile_ready = TRUE
update_icons()
throw_at(new_turf, max(3,get_dist(src,new_turf)), 1, src, FALSE, callback = CALLBACK(src, .FinishHop))
/mob/living/simple_animal/hostile/jungle/leaper/proc/FinishHop()
density = TRUE
notransform = FALSE
pass_flags &= ~PASSMOB
hopping = FALSE
playsound(src.loc, 'sound/effects/meteorimpact.ogg', 100, 1)
if(target && AIStatus == AI_ON && projectile_ready && !ckey)
face_atom(target)
addtimer(CALLBACK(src, .proc/OpenFire, target), 5)
/mob/living/simple_animal/hostile/jungle/leaper/proc/BellyFlop()
var/turf/new_turf = get_turf(target)
hopping = TRUE
notransform = TRUE
new /obj/effect/temp_visual/leaper_crush(new_turf)
addtimer(CALLBACK(src, .proc/BellyFlopHop, new_turf), 30)
/mob/living/simple_animal/hostile/jungle/leaper/proc/BellyFlopHop(turf/T)
density = FALSE
throw_at(T, get_dist(src,T),1,src, FALSE, callback = CALLBACK(src, .proc/Crush))
/mob/living/simple_animal/hostile/jungle/leaper/proc/Crush()
hopping = FALSE
density = TRUE
notransform = FALSE
playsound(src, 'sound/effects/meteorimpact.ogg', 200, 1)
for(var/mob/living/L in orange(1, src))
L.adjustBruteLoss(35)
if(!QDELETED(L)) // Some mobs are deleted on death
var/throw_dir = get_dir(src, L)
if(L.loc == loc)
throw_dir = pick(GLOB.alldirs)
var/throwtarget = get_edge_target_turf(src, throw_dir)
L.throw_at(throwtarget, 3, 1)
visible_message("<span class='warning'>[L] is thrown clear of [src]!</span>")
if(ckey)//Lessens ability to chain stun as a player
ranged_cooldown = ranged_cooldown_time + world.time
update_icons()
/mob/living/simple_animal/hostile/jungle/leaper/Goto()
return
/mob/living/simple_animal/hostile/jungle/leaper/throw_impact()
return
/mob/living/simple_animal/hostile/jungle/leaper/update_icons()
. = ..()
if(stat)
icon_state = "leaper_dead"
return
if(ranged_cooldown <= world.time)
if(AIStatus == AI_ON && projectile_ready || ckey)
icon_state = "leaper_alert"
return
icon_state = "leaper"
#undef PLAYER_HOP_DELAY
////JUNGLE MOOK////
#define MOOK_ATTACK_NEUTRAL 0
#define MOOK_ATTACK_WARMUP 1
#define MOOK_ATTACK_ACTIVE 2
#define MOOK_ATTACK_RECOVERY 3
#define ATTACK_INTERMISSION_TIME 5
/mob/living/simple_animal/hostile/jungle/mook
name = "wanderer"
desc = "This unhealthy looking primitive is wielding a rudimentary hatchet, swinging it with wild abandon. One isn't much of a threat, but in numbers they can quickly overwhelm a superior opponent."
maxHealth = 45
health = 45
melee_damage_lower = 30
melee_damage_upper = 30
icon = 'icons/mob/jungle/arachnid.dmi'
icon_state = "mook"
icon_living = "mook"
icon_dead = "mook_dead"
pixel_x = -16
pixel_y = -8
ranged = TRUE
ranged_cooldown_time = 10
pass_flags = LETPASSTHROW
robust_searching = TRUE
stat_attack = UNCONSCIOUS
attack_sound = 'sound/weapons/rapierhit.ogg'
death_sound = 'sound/voice/mook_death.ogg'
aggro_vision_range = 15 //A little more aggressive once in combat to balance out their really low HP
var/attack_state = MOOK_ATTACK_NEUTRAL
var/struck_target_leap = FALSE
/mob/living/simple_animal/hostile/jungle/mook/CanPass(atom/movable/O)
if(istype(O, /mob/living/simple_animal/hostile/jungle/mook))
var/mob/living/simple_animal/hostile/jungle/mook/M = O
if(M.attack_state == MOOK_ATTACK_ACTIVE && M.throwing)
return TRUE
return ..()
/mob/living/simple_animal/hostile/jungle/mook/death()
desc = "A deceased primitive. Upon closer inspection, it was suffering from severe cellular degeneration and its garments are machine made..."//Can you guess the twist
return ..()
/mob/living/simple_animal/hostile/jungle/mook/AttackingTarget()
if(isliving(target))
if(ranged_cooldown <= world.time && attack_state == MOOK_ATTACK_NEUTRAL)
var/mob/living/L = target
if(L.incapacitated())
WarmupAttack(forced_slash_combo = TRUE)
return
WarmupAttack()
return
return ..()
/mob/living/simple_animal/hostile/jungle/mook/Goto()
if(attack_state != MOOK_ATTACK_NEUTRAL)
return
return ..()
/mob/living/simple_animal/hostile/jungle/mook/Move()
if(attack_state == MOOK_ATTACK_WARMUP || attack_state == MOOK_ATTACK_RECOVERY)
return
return ..()
/mob/living/simple_animal/hostile/jungle/mook/proc/WarmupAttack(forced_slash_combo = FALSE)
if(attack_state == MOOK_ATTACK_NEUTRAL && target)
attack_state = MOOK_ATTACK_WARMUP
walk(src,0)
update_icons()
if(prob(50) && get_dist(src,target) <= 3 || forced_slash_combo)
addtimer(CALLBACK(src, .proc/SlashCombo), ATTACK_INTERMISSION_TIME)
return
addtimer(CALLBACK(src, .proc/LeapAttack), ATTACK_INTERMISSION_TIME + rand(0,3))
return
attack_state = MOOK_ATTACK_RECOVERY
ResetNeutral()
/mob/living/simple_animal/hostile/jungle/mook/proc/SlashCombo()
if(attack_state == MOOK_ATTACK_WARMUP && !stat)
attack_state = MOOK_ATTACK_ACTIVE
update_icons()
SlashAttack()
addtimer(CALLBACK(src, .proc/SlashAttack), 3)
addtimer(CALLBACK(src, .proc/SlashAttack), 6)
addtimer(CALLBACK(src, .proc/AttackRecovery), 9)
/mob/living/simple_animal/hostile/jungle/mook/proc/SlashAttack()
if(target && !stat && attack_state == MOOK_ATTACK_ACTIVE)
melee_damage_lower = 15
melee_damage_upper = 15
var/mob_direction = get_dir(src,target)
if(get_dist(src,target) > 1)
step(src,mob_direction)
if(targets_from && isturf(targets_from.loc) && target.Adjacent(targets_from) && isliving(target))
var/mob/living/L = target
L.attack_animal(src)
return
var/swing_turf = get_step(src,mob_direction)
new /obj/effect/temp_visual/kinetic_blast(swing_turf)
playsound(src, 'sound/weapons/slashmiss.ogg', 50, 1)
/mob/living/simple_animal/hostile/jungle/mook/proc/LeapAttack()
if(target && !stat && attack_state == MOOK_ATTACK_WARMUP)
attack_state = MOOK_ATTACK_ACTIVE
density = FALSE
melee_damage_lower = 30
melee_damage_upper = 30
update_icons()
new /obj/effect/temp_visual/mook_dust(get_turf(src))
playsound(src, 'sound/weapons/thudswoosh.ogg', 25, 1)
playsound(src, 'sound/voice/mook_leap_yell.ogg', 100, 1)
var/target_turf = get_turf(target)
throw_at(target_turf, 7, 1, src, FALSE, callback = CALLBACK(src, .proc/AttackRecovery))
return
attack_state = MOOK_ATTACK_RECOVERY
ResetNeutral()
/mob/living/simple_animal/hostile/jungle/mook/proc/AttackRecovery()
if(attack_state == MOOK_ATTACK_ACTIVE && !stat)
attack_state = MOOK_ATTACK_RECOVERY
density = TRUE
face_atom(target)
if(!struck_target_leap)
update_icons()
struck_target_leap = FALSE
if(prob(40))
attack_state = MOOK_ATTACK_NEUTRAL
if(target)
if(isliving(target))
var/mob/living/L = target
if(L.incapacitated() && L.stat != DEAD)
addtimer(CALLBACK(src, .proc/WarmupAttack, TRUE), ATTACK_INTERMISSION_TIME)
return
addtimer(CALLBACK(src, .proc/WarmupAttack), ATTACK_INTERMISSION_TIME)
return
addtimer(CALLBACK(src, .proc/ResetNeutral), ATTACK_INTERMISSION_TIME)
/mob/living/simple_animal/hostile/jungle/mook/proc/ResetNeutral()
if(attack_state == MOOK_ATTACK_RECOVERY)
attack_state = MOOK_ATTACK_NEUTRAL
ranged_cooldown = world.time + ranged_cooldown_time
update_icons()
if(target && !stat)
update_icons()
Goto(target, move_to_delay, minimum_distance)
/mob/living/simple_animal/hostile/jungle/mook/throw_impact(atom/hit_atom, throwingdatum)
. = ..()
if(isliving(hit_atom) && attack_state == MOOK_ATTACK_ACTIVE)
var/mob/living/L = hit_atom
if(CanAttack(L))
L.attack_animal(src)
struck_target_leap = TRUE
density = TRUE
update_icons()
var/mook_under_us = FALSE
for(var/A in get_turf(src))
if(struck_target_leap && mook_under_us)
break
if(A == src)
continue
if(isliving(A))
var/mob/living/ML = A
if(!struck_target_leap && CanAttack(ML))//Check if some joker is attempting to use rest to evade us
struck_target_leap = TRUE
ML.attack_animal(src)
density = TRUE
struck_target_leap = TRUE
update_icons()
continue
if(istype(ML, /mob/living/simple_animal/hostile/jungle/mook) && !mook_under_us)//If we land on the same tile as another mook, spread out so we don't stack our sprite on the same tile
var/mob/living/simple_animal/hostile/jungle/mook/M = ML
if(!M.stat)
mook_under_us = TRUE
var/anydir = pick(GLOB.cardinals)
Move(get_step(src, anydir), anydir)
continue
/mob/living/simple_animal/hostile/jungle/mook/handle_automated_action()
if(attack_state)
return
return ..()
/mob/living/simple_animal/hostile/jungle/mook/OpenFire()
if(isliving(target))
var/mob/living/L = target
if(L.incapacitated())
return
WarmupAttack()
/mob/living/simple_animal/hostile/jungle/mook/update_icons()
. = ..()
if(!stat)
switch(attack_state)
if(MOOK_ATTACK_NEUTRAL)
icon_state = "mook"
if(MOOK_ATTACK_WARMUP)
icon_state = "mook_warmup"
if(MOOK_ATTACK_ACTIVE)
if(!density)
icon_state = "mook_leap"
return
if(struck_target_leap)
icon_state = "mook_strike"
return
icon_state = "mook_slash_combo"
if(MOOK_ATTACK_RECOVERY)
icon_state = "mook"
/obj/effect/temp_visual/mook_dust
name = "dust"
desc = "it's just a dust cloud!"
icon = 'icons/mob/jungle/arachnid.dmi'
icon_state = "mook_leap_cloud"
layer = BELOW_MOB_LAYER
pixel_x = -16
pixel_y = -16
duration = 10
#undef MOOK_ATTACK_NEUTRAL
#undef MOOK_ATTACK_WARMUP
#undef MOOK_ATTACK_ACTIVE
#undef MOOK_ATTACK_RECOVERY
#undef ATTACK_INTERMISSION_TIME
////Jungle Seedling////
#define SEEDLING_STATE_NEUTRAL 0
#define SEEDLING_STATE_WARMUP 1
#define SEEDLING_STATE_ACTIVE 2
#define SEEDLING_STATE_RECOVERY 3
/mob/living/simple_animal/hostile/jungle/seedling
name = "seedling"
desc = "This oversized, predatory flower conceals what can only be described as an organic energy cannon, and it will not die until its hidden vital organs are sliced out. \
The concentrated streams of energy it sometimes produces require its full attention, attacking it during this time will prevent it from finishing its attack."
maxHealth = 100
health = 100
melee_damage_lower = 30
melee_damage_upper = 30
icon = 'icons/mob/jungle/arachnid.dmi'
icon_state = "seedling"
icon_living = "seedling"
icon_dead = "seedling_dead"
pixel_x = -16
pixel_y = -14
minimum_distance = 3
move_to_delay = 20
vision_range = 9
aggro_vision_range = 15
ranged = TRUE
ranged_cooldown_time = 10
projectiletype = /obj/item/projectile/seedling
projectilesound = 'sound/weapons/pierce.ogg'
robust_searching = TRUE
stat_attack = UNCONSCIOUS
anchored = TRUE
var/combatant_state = SEEDLING_STATE_NEUTRAL
var/obj/seedling_weakpoint/weak_point
var/mob/living/beam_debuff_target
var/solar_beam_identifier = 0
/obj/item/projectile/seedling
name = "solar energy"
icon_state = "seedling"
damage = 10
damage_type = BURN
light_range = 2
flag = "energy"
light_color = LIGHT_COLOR_YELLOW
hitsound = 'sound/weapons/sear.ogg'
hitsound_wall = 'sound/weapons/effects/searwall.ogg'
nondirectional_sprite = TRUE
/obj/item/projectile/seedling/Collide(atom/A)//Stops seedlings from destroying other jungle mobs through FF
if(isliving(A))
var/mob/living/L = A
if("jungle" in L.faction)
return FALSE
return ..()
/obj/effect/temp_visual/solarbeam_killsat
name = "beam of solar energy"
icon_state = "solar_beam"
icon = 'icons/effects/beam.dmi'
layer = LIGHTING_LAYER
duration = 5
randomdir = FALSE
/datum/status_effect/seedling_beam_indicator
id = "seedling beam indicator"
duration = 30
status_type = STATUS_EFFECT_MULTIPLE
alert_type = null
tick_interval = 1
var/obj/screen/seedling/seedling_screen_object
var/atom/target
/datum/status_effect/seedling_beam_indicator/on_creation(mob/living/new_owner, target_plant)
. = ..()
if(.)
target = target_plant
tick()
/datum/status_effect/seedling_beam_indicator/on_apply()
if(owner.client)
seedling_screen_object = new /obj/screen/seedling()
owner.client.screen += seedling_screen_object
tick()
return ..()
/datum/status_effect/seedling_beam_indicator/Destroy()
if(owner)
if(owner.client)
owner.client.screen -= seedling_screen_object
return ..()
/datum/status_effect/seedling_beam_indicator/tick()
var/target_angle = Get_Angle(owner, target)
var/matrix/final = matrix()
final.Turn(target_angle)
seedling_screen_object.transform = final
/obj/screen/seedling
icon = 'icons/mob/jungle/arachnid.dmi'
icon_state = "seedling_beam_indicator"
screen_loc = "CENTER:-16,CENTER:-16"
/mob/living/simple_animal/hostile/jungle/seedling/Goto()
if(combatant_state != SEEDLING_STATE_NEUTRAL)
return
return ..()
/mob/living/simple_animal/hostile/jungle/seedling/AttackingTarget()
if(isliving(target))
if(ranged_cooldown <= world.time && combatant_state == SEEDLING_STATE_NEUTRAL)
OpenFire(target)
return
return ..()
/mob/living/simple_animal/hostile/jungle/seedling/OpenFire()
WarmupAttack()
/mob/living/simple_animal/hostile/jungle/seedling/proc/WarmupAttack()
if(combatant_state == SEEDLING_STATE_NEUTRAL)
combatant_state = SEEDLING_STATE_WARMUP
walk(src,0)
update_icons()
var/target_dist = get_dist(src,target)
var/living_target_check = isliving(target)
if(living_target_check)
if(target_dist > 7)//Offscreen check
SolarBeamStartup(target)
return
if(get_dist(src,target) >= 4 && prob(40))
SolarBeamStartup(target)
return
addtimer(CALLBACK(src, .proc/Volley), 5)
/mob/living/simple_animal/hostile/jungle/seedling/proc/SolarBeamStartup(mob/living/living_target)//It's more like requiem than final spark
if(combatant_state == SEEDLING_STATE_WARMUP && target)
combatant_state = SEEDLING_STATE_ACTIVE
living_target.apply_status_effect(/datum/status_effect/seedling_beam_indicator, src)
beam_debuff_target = living_target
playsound(src,'sound/effects/seedling_chargeup.ogg', 100, 0)
if(get_dist(src,living_target) > 7)
playsound(living_target,'sound/effects/seedling_chargeup.ogg', 100, 0)
solar_beam_identifier = world.time
addtimer(CALLBACK(src, .proc/Beamu, living_target, solar_beam_identifier), 35)
/mob/living/simple_animal/hostile/jungle/seedling/proc/Beamu(mob/living/living_target, beam_id = 0)
if(combatant_state == SEEDLING_STATE_ACTIVE && living_target && beam_id == solar_beam_identifier)
if(living_target.z == z)
update_icons()
var/obj/effect/temp_visual/solarbeam_killsat/S = new (get_turf(src))
var/matrix/starting = matrix()
starting.Scale(1,32)
starting.Translate(0,520)
S.transform = starting
var/obj/effect/temp_visual/solarbeam_killsat/K = new (get_turf(living_target))
var/matrix/final = matrix()
final.Scale(1,32)
final.Translate(0,512)
K.transform = final
living_target.adjustFireLoss(30)
living_target.adjust_fire_stacks(0.2)//Just here for the showmanship
living_target.IgniteMob()
playsound(living_target,'sound/weapons/sear.ogg', 50, 1)
addtimer(CALLBACK(src, .proc/AttackRecovery), 5)
return
AttackRecovery()
/mob/living/simple_animal/hostile/jungle/seedling/proc/Volley()
if(combatant_state == SEEDLING_STATE_WARMUP && target)
combatant_state = SEEDLING_STATE_ACTIVE
update_icons()
var/datum/callback/cb = CALLBACK(src, .proc/InaccurateShot)
for(var/i in 1 to 13)
addtimer(cb, i)
addtimer(CALLBACK(src, .proc/AttackRecovery), 14)
/mob/living/simple_animal/hostile/jungle/seedling/proc/InaccurateShot()
if(!QDELETED(target) && combatant_state == SEEDLING_STATE_ACTIVE && !stat)
if(get_dist(src,target) <= 3)//If they're close enough just aim straight at them so we don't miss at point blank ranges
Shoot(target)
return
var/turf/our_turf = get_turf(src)
var/obj/item/projectile/seedling/readied_shot = new /obj/item/projectile/seedling(our_turf)
readied_shot.current = our_turf
readied_shot.starting = our_turf
readied_shot.firer = src
readied_shot.original = target
readied_shot.yo = target.y - our_turf.y + rand(-1,1)
readied_shot.xo = target.x - our_turf.x + rand(-1,1)
readied_shot.fire()
playsound(src, projectilesound, 100, 1)
/mob/living/simple_animal/hostile/jungle/seedling/proc/AttackRecovery()
if(combatant_state == SEEDLING_STATE_ACTIVE)
combatant_state = SEEDLING_STATE_RECOVERY
update_icons()
ranged_cooldown = world.time + ranged_cooldown_time
if(target)
face_atom(target)
addtimer(CALLBACK(src, .proc/ResetNeutral), 10)
/mob/living/simple_animal/hostile/jungle/seedling/proc/ResetNeutral()
combatant_state = SEEDLING_STATE_NEUTRAL
if(target && !stat)
update_icons()
Goto(target, move_to_delay, minimum_distance)
/mob/living/simple_animal/hostile/jungle/seedling/adjustHealth()
. = ..()
if(combatant_state == SEEDLING_STATE_ACTIVE && beam_debuff_target)
beam_debuff_target.remove_status_effect(/datum/status_effect/seedling_beam_indicator)
beam_debuff_target = null
solar_beam_identifier = 0
AttackRecovery()
/mob/living/simple_animal/hostile/jungle/seedling/update_icons()
. = ..()
if(!stat)
switch(combatant_state)
if(SEEDLING_STATE_NEUTRAL)
icon_state = "seedling"
if(SEEDLING_STATE_WARMUP)
icon_state = "seedling_charging"
if(SEEDLING_STATE_ACTIVE)
icon_state = "seedling_fire"
if(SEEDLING_STATE_RECOVERY)
icon_state = "seedling"
/mob/living/simple_animal/hostile/jungle/seedling/GiveTarget()
if(target)
if(combatant_state == SEEDLING_STATE_WARMUP || combatant_state == SEEDLING_STATE_ACTIVE)//So it doesn't 180 and blast you in the face while it's firing at someone else
return
return ..()
/mob/living/simple_animal/hostile/jungle/seedling/LoseTarget()
if(combatant_state == SEEDLING_STATE_WARMUP || combatant_state == SEEDLING_STATE_ACTIVE)
return
return ..()
#undef SEEDLING_STATE_NEUTRAL
#undef SEEDLING_STATE_WARMUP
#undef SEEDLING_STATE_ACTIVE
#undef SEEDLING_STATE_RECOVERY

Binary file not shown.

Before

Width:  |  Height:  |  Size: 65 KiB

After

Width:  |  Height:  |  Size: 20 KiB

BIN
icons/mob/jungle/leaper.dmi Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 6.3 KiB

BIN
icons/mob/jungle/mook.dmi Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 23 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 11 KiB

View File

@@ -1725,7 +1725,6 @@
#include "code\modules\mob\living\simple_animal\hostile\hivebot.dm"
#include "code\modules\mob\living\simple_animal\hostile\hostile.dm"
#include "code\modules\mob\living\simple_animal\hostile\illusion.dm"
#include "code\modules\mob\living\simple_animal\hostile\jungle_mobs.dm"
#include "code\modules\mob\living\simple_animal\hostile\killertomato.dm"
#include "code\modules\mob\living\simple_animal\hostile\mecha_pilot.dm"
#include "code\modules\mob\living\simple_animal\hostile\mimic.dm"
@@ -1746,6 +1745,11 @@
#include "code\modules\mob\living\simple_animal\hostile\gorilla\emotes.dm"
#include "code\modules\mob\living\simple_animal\hostile\gorilla\gorilla.dm"
#include "code\modules\mob\living\simple_animal\hostile\gorilla\visuals_icons.dm"
#include "code\modules\mob\living\simple_animal\hostile\jungle\_jungle_mobs.dm"
#include "code\modules\mob\living\simple_animal\hostile\jungle\leaper.dm"
#include "code\modules\mob\living\simple_animal\hostile\jungle\mega_arachnid.dm"
#include "code\modules\mob\living\simple_animal\hostile\jungle\mook.dm"
#include "code\modules\mob\living\simple_animal\hostile\jungle\seedling.dm"
#include "code\modules\mob\living\simple_animal\hostile\megafauna\blood_drunk_miner.dm"
#include "code\modules\mob\living\simple_animal\hostile\megafauna\bubblegum.dm"
#include "code\modules\mob\living\simple_animal\hostile\megafauna\colossus.dm"