Converts Pirates, Soviets, and Drakehounds to basic mob AI (#29903)

* Converts pirates, soviets, and drakehounds to basic mob AI

* Linters and fixes

* Pirate fire rate adjustment

* Merge fixes

* Better ranged attack code

* Even better ranged code

---------

Signed-off-by: PollardTheDragon <144391971+PollardTheDragon@users.noreply.github.com>
Signed-off-by: Burzah <116982774+Burzah@users.noreply.github.com>
Co-authored-by: Burzah <116982774+Burzah@users.noreply.github.com>
This commit is contained in:
PollardTheDragon
2025-08-06 06:30:29 +00:00
committed by GitHub
co-authored by Burzah
parent a6edafaa2e
commit 6701e12613
25 changed files with 554 additions and 270 deletions
+4 -1
View File
@@ -162,6 +162,9 @@ RESTRICT_TYPE(/mob/living/basic)
var/ranged_burst_interval = 0.2 SECONDS
/// Time between bursts
var/ranged_cooldown = 2 SECONDS
/// What casing type is the projectile?
var/casing_type
/// What projectile do we shoot?
var/projectile_type
/// What sound does it make when firing?
@@ -181,7 +184,7 @@ RESTRICT_TYPE(/mob/living/basic)
var/datum/action/innate/hide/hide = new()
hide.Grant(src)
if(is_ranged)
AddComponent(/datum/component/ranged_attacks, cooldown_time = ranged_cooldown, projectile_type = projectile_type, projectile_sound = projectile_sound, burst_shots = ranged_burst_count, burst_intervals = ranged_burst_interval)
AddComponent(/datum/component/ranged_attacks, casing_type = casing_type, projectile_type = projectile_type, projectile_sound = projectile_sound, burst_shots = ranged_burst_count, burst_intervals = ranged_burst_interval, cooldown_time = ranged_cooldown)
/mob/living/basic/Destroy()
if(nest)
@@ -0,0 +1,78 @@
/mob/living/basic/drakehound_breacher
name = "Drakehound Breacher"
desc = "A unathi raider with a viscious streak."
icon = 'icons/mob/simple_human.dmi'
icon_state = "drakehound"
icon_living = "drakehound"
icon_dead = "drakehound_dead" // Does not actually exist. del_on_death.
mob_biotypes = MOB_ORGANIC | MOB_HUMANOID
response_help_continuous = "pushes the"
response_help_continuous = "push the"
response_harm_continuous = "slashes"
response_harm_simple = "slash"
speed = 0
harm_intent_damage = 5
obj_damage = 60
melee_damage_lower = 30
melee_damage_upper = 30
melee_attack_cooldown_min = 1.5 SECONDS
melee_attack_cooldown_max = 2.5 SECONDS
attack_verb_continuous = "slashes"
attack_verb_simple = "slash"
attack_sound = 'sound/weapons/bladeslice.ogg'
minimum_survivable_temperature = 0
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)
speak_emote = list("hisses")
ai_controller = /datum/ai_controller/basic_controller/simple/drakehound
loot = list(
/obj/effect/mob_spawn/human/corpse/drakehound,
/obj/effect/decal/cleanable/blood/innards,
/obj/effect/decal/cleanable/blood,
/obj/effect/gibspawner/generic,
/obj/effect/gibspawner/generic)
basic_mob_flags = DEL_ON_DEATH
faction = list("pirate")
sentience_type = SENTIENCE_OTHER
step_type = FOOTSTEP_MOB_SHOE
/mob/living/basic/drakehound_breacher/Initialize(mapload)
. = ..()
add_language("Sinta'unathi")
set_default_language(GLOB.all_languages["Sinta'unathi"])
AddComponent(/datum/component/aggro_emote, aggro_sound = 'sound/effects/unathihiss.ogg', emote_chance = 100)
if(prob(50))
loot = list(
/obj/item/salvage/loot/pirate,
/obj/effect/mob_spawn/human/corpse/drakehound,
/obj/effect/decal/cleanable/blood/innards,
/obj/effect/decal/cleanable/blood,
/obj/effect/gibspawner/generic,
/obj/effect/gibspawner/generic)
/mob/living/basic/drakehound_breacher/Process_Spacemove(movement_dir = 0, continuous_move = FALSE)
return TRUE
/datum/ai_controller/basic_controller/simple/drakehound
blackboard = list(
BB_TARGETING_STRATEGY = /datum/targeting_strategy/basic,
BB_TARGET_MINIMUM_STAT = UNCONSCIOUS,
)
planning_subtrees = list(
/datum/ai_planning_subtree/random_speech/drakehound,
/datum/ai_planning_subtree/simple_find_target,
/datum/ai_planning_subtree/attack_obstacle_in_path,
/datum/ai_planning_subtree/basic_melee_attack_subtree,
)
/datum/ai_planning_subtree/random_speech/drakehound
speech_chance = 10
speak = list(
"I'll send you back to the pits!",
"Finally, some action!",
"You're gonna be quick work!",
"Oh, now you fucked up!",
"Maybe don't board the clearly dangerous looking ship?",
"Heart Smash is better, you don't know good music.",
"We wouldn't be stuck here if we just zigged when we zagged.",
"Well, atleast I'm away from my brother!",
"Got any smokes?")
@@ -0,0 +1,119 @@
/mob/living/basic/pirate
name = "Pirate"
desc = "Does what he wants cause a pirate is free."
icon = 'icons/mob/simple_human.dmi'
icon_state = "piratespace"
icon_living = "piratespace"
icon_dead = "piratemelee_dead" // Does not actually exist. del_on_death.
mob_biotypes = MOB_ORGANIC | MOB_HUMANOID
death_sound = 'sound/creatures/piratedeath.ogg'
response_help_continuous = "pushes the"
response_help_continuous = "push the"
response_harm_continuous = "slashes"
response_harm_simple = "slash"
speed = 0
harm_intent_damage = 5
obj_damage = 60
melee_damage_lower = 30
melee_damage_upper = 30
melee_attack_cooldown_min = 1.5 SECONDS
melee_attack_cooldown_max = 2.5 SECONDS
attack_verb_continuous = "slashes"
attack_verb_simple = "slash"
attack_sound = 'sound/weapons/blade1.ogg'
minimum_survivable_temperature = 0
ai_controller = /datum/ai_controller/basic_controller/simple/pirate
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)
speak_emote = list("yarrs")
loot = list(/obj/item/melee/energy/sword/pirate,
/obj/item/clothing/head/helmet/space/pirate,
/obj/effect/mob_spawn/human/corpse/pirate,
/obj/effect/decal/cleanable/blood/innards,
/obj/effect/decal/cleanable/blood,
/obj/effect/gibspawner/generic,
/obj/effect/gibspawner/generic)
basic_mob_flags = DEL_ON_DEATH
faction = list("pirate")
sentience_type = SENTIENCE_OTHER
step_type = FOOTSTEP_MOB_SHOE
/mob/living/basic/pirate/Initialize(mapload)
. = ..()
AddComponent(/datum/component/aggro_emote, aggro_sound = 'sound/creatures/pirateengage.ogg', emote_chance = 100)
add_language("Galactic Common")
set_default_language(GLOB.all_languages["Galactic Common"])
if(prob(50))
loot = list(/obj/item/clothing/head/helmet/space/pirate,
/obj/item/salvage/loot/pirate,
/obj/effect/mob_spawn/human/corpse/pirate,
/obj/effect/decal/cleanable/blood/innards,
/obj/effect/decal/cleanable/blood,
/obj/effect/gibspawner/generic,
/obj/effect/gibspawner/generic)
/mob/living/basic/pirate/Process_Spacemove(movement_dir = 0, continuous_move = FALSE)
return TRUE
/mob/living/basic/pirate/ranged
name = "Pirate Gunner"
icon_state = "piratespaceranged"
icon_living = "piratespaceranged"
is_ranged = TRUE
projectile_type = /obj/item/projectile/beam
projectile_sound = 'sound/weapons/laser.ogg'
ranged_burst_count = 2
ranged_burst_interval = 0.5 SECONDS // Same fire rate as people!
ai_controller = /datum/ai_controller/basic_controller/simple/pirate/ranged
loot = list(/obj/effect/mob_spawn/human/corpse/pirate,
/obj/item/gun/energy/laser,
/obj/item/clothing/head/helmet/space/pirate,
/obj/effect/decal/cleanable/blood/innards,
/obj/effect/decal/cleanable/blood,
/obj/effect/gibspawner/generic,
/obj/effect/gibspawner/generic)
/mob/living/basic/pirate/ranged/Initialize(mapload)
. = ..()
if(prob(50))
loot = list(/obj/item/clothing/head/helmet/space/pirate,
/obj/item/salvage/loot/pirate,
/obj/effect/mob_spawn/human/corpse/pirate,
/obj/effect/decal/cleanable/blood/innards,
/obj/effect/decal/cleanable/blood,
/obj/effect/gibspawner/generic,
/obj/effect/gibspawner/generic)
/datum/ai_controller/basic_controller/simple/pirate
blackboard = list(
BB_TARGETING_STRATEGY = /datum/targeting_strategy/basic,
BB_TARGET_MINIMUM_STAT = UNCONSCIOUS,
)
planning_subtrees = list(
/datum/ai_planning_subtree/random_speech/pirate,
/datum/ai_planning_subtree/simple_find_target,
/datum/ai_planning_subtree/attack_obstacle_in_path,
/datum/ai_planning_subtree/basic_melee_attack_subtree,
)
/datum/ai_planning_subtree/random_speech/pirate
speech_chance = 10
speak = list(
"Arrrg!",
"Avast!",
"Shiver me timbers!",
"Yo ho ho!",
"Where's the rum gone?",
"Dead men tell no tales!",
"Scurvy dog!",
"Weigh anchor!",
"Raise the Jolly Rodger!",
"No quarter!")
/datum/ai_controller/basic_controller/simple/pirate/ranged
planning_subtrees = list(
/datum/ai_planning_subtree/random_speech/pirate,
/datum/ai_planning_subtree/simple_find_target,
/datum/ai_planning_subtree/basic_melee_attack_subtree/opportunistic,
/datum/ai_planning_subtree/maintain_distance,
/datum/ai_planning_subtree/ranged_skirmish/avoid_friendly,
)
@@ -0,0 +1,103 @@
/mob/living/basic/soviet
name = "Soviet"
desc = "For the Union!"
icon = 'icons/mob/simple_human.dmi'
icon_state = "sovietmelee"
icon_living = "sovietmelee"
icon_dead = "sovietmelee_dead" // Does not actually exist. del_on_death.
icon_gib = "sovietmelee_gib" // Does not actually exist. del_on_death.
mob_biotypes = MOB_ORGANIC | MOB_HUMANOID
speed = 0
harm_intent_damage = 5
melee_damage_lower = 15
melee_damage_upper = 15
melee_attack_cooldown_min = 1.5 SECONDS
melee_attack_cooldown_max = 2.5 SECONDS
attack_verb_continuous = "punches"
attack_verb_simple = "punch"
attack_sound = 'sound/weapons/bladeslice.ogg'
a_intent = INTENT_HARM
unsuitable_atmos_damage = 15
ai_controller = /datum/ai_controller/basic_controller/simple/soviet
faction = list("soviet")
loot = list(/obj/effect/mob_spawn/human/corpse/soviet,
/obj/item/kitchen/knife,
/obj/item/salvage/loot/soviet)
basic_mob_flags = DEL_ON_DEATH
sentience_type = SENTIENCE_OTHER
step_type = FOOTSTEP_MOB_SHOE
/mob/living/basic/soviet/Initialize(mapload)
. = ..()
add_language("Zvezhan")
set_default_language(GLOB.all_languages["Zvezhan"])
/mob/living/basic/soviet/ranged
icon_state = "sovietranged"
icon_living = "sovietranged"
is_ranged = TRUE
casing_type = /obj/item/ammo_casing/a357
ranged_cooldown = 4 SECONDS
projectile_sound = 'sound/weapons/gunshots/gunshot.ogg'
loot = list(/obj/effect/mob_spawn/human/corpse/soviet/ranged, /obj/item/gun/projectile/revolver/mateba)
ai_controller = /datum/ai_controller/basic_controller/simple/soviet/ranged
/mob/living/basic/soviet/ranged/mosin
loot = list(/obj/effect/mob_spawn/human/corpse/soviet/ranged,
/obj/item/gun/projectile/shotgun/boltaction,
/obj/item/salvage/loot/soviet)
casing_type = /obj/item/ammo_casing/a762
projectile_sound = 'sound/weapons/gunshots/gunshot_rifle.ogg'
/mob/living/basic/soviet/nian
name = "Soviet Nian"
desc = "Buzz!"
icon_state = "sovietnian"
icon_living = "sovietnian"
obj_damage = 60
melee_damage_lower = 30
melee_damage_upper = 30
attack_verb_continuous = "slashes"
attack_verb_simple = "slash"
attack_sound = 'sound/weapons/blade1.ogg'
minimum_survivable_temperature = 0
loot = list(
/obj/effect/mob_spawn/human/corpse/soviet_nian,
/obj/item/melee/energy/sword/pirate,
/obj/item/salvage/loot/soviet
)
/datum/ai_controller/basic_controller/simple/soviet
blackboard = list(
BB_TARGETING_STRATEGY = /datum/targeting_strategy/basic,
BB_TARGET_MINIMUM_STAT = UNCONSCIOUS,
)
planning_subtrees = list(
/datum/ai_planning_subtree/random_speech/soviet,
/datum/ai_planning_subtree/simple_find_target,
/datum/ai_planning_subtree/attack_obstacle_in_path,
/datum/ai_planning_subtree/basic_melee_attack_subtree,
)
/datum/ai_controller/basic_controller/simple/soviet/ranged
planning_subtrees = list(
/datum/ai_planning_subtree/random_speech/soviet,
/datum/ai_planning_subtree/simple_find_target,
/datum/ai_planning_subtree/basic_melee_attack_subtree/opportunistic,
/datum/ai_planning_subtree/maintain_distance,
/datum/ai_planning_subtree/ranged_skirmish/avoid_friendly,
)
/datum/ai_planning_subtree/random_speech/soviet
speech_chance = 10
speak = list(
"We work for the future.",
"The party leads us forward.",
"Long live socialism!",
"One people, one purpse!",
"For the state!",
"Forward to communism!",
"Glory to the worker!",
"With sweat we strengthen the state!",
"From each, according to ability!",
"We forge tomorrow with our hands!")