From 9e18c6575a3cb9e73c3e699d4fe51b904b76e2f6 Mon Sep 17 00:00:00 2001 From: lizardqueenlexi <105025397+lizardqueenlexi@users.noreply.github.com> Date: Sun, 29 Oct 2023 21:27:46 -0500 Subject: [PATCH] Basic Pirate NPCs (#79284) ## About The Pull Request Converts hostile pirate NPCs to basic mobs - specifically, a subtype of trooper. As their behavior is not meaningfully distinct from other troopers, this conversion mostly just sticks them on the existing AI behavior while keeping the rest the same. Pirates do have one new thing going for them, though, to differentiate them from other troopers. They use the new **plundering attacks** component, which means that every time they land a melee attack, they steal money from the bank account of whoever they hit. This requires the target to be wearing an ID with a linked bank account, so it's not the hardest thing in the world to hide your money from them - but it's still something to be wary of! If killed, any mob with this component will drop everything they've stolen in a convenient holochip. ## Why It's Good For The Game Takes down 5 more simplemobs, and (I think) converts the last remaining trooper-type enemy to be a basic trooper. (It's possible there's more I've forgotten that could use the same AI, though.) The money-stealing behavior is mostly good because I think it's funny, but it also makes the pirates something a little distinct from "yet another mob that runs at you and punches you until you die". They still do that, but now there's a little twist! This can be placed on other mobs too, if we want to make any other sorts of thieves or brigands. ## Changelog :cl: refactor: Pirate NPCs now use the basic mob framework. They'll be a little smarter in combat, and if you're wearing your ID they'll siphon your bank account with every melee attack! Beware! Please report any bugs. /:cl: --- .../RandomRuins/SpaceRuins/caravanambush.dmm | 8 +- .../SpaceRuins/derelict_construction.dmm | 4 +- _maps/shuttles/ruin_pirate_cutter.dmm | 6 +- _maps/virtual_domains/pirates.dmm | 14 +-- code/datums/components/plundering_attacks.dm | 54 +++++++++++ .../mob/living/basic/trooper/pirate.dm | 89 ++++++++++++++++++ .../mob/living/basic/trooper/syndicate.dm | 2 - .../living/simple_animal/hostile/pirate.dm | 91 ------------------- .../unit_tests/simple_animal_freeze.dm | 5 - tgstation.dme | 3 +- .../Scripts/79284_simple_to_basic_pirates.txt | 1 + 11 files changed, 162 insertions(+), 115 deletions(-) create mode 100644 code/datums/components/plundering_attacks.dm create mode 100644 code/modules/mob/living/basic/trooper/pirate.dm delete mode 100644 code/modules/mob/living/simple_animal/hostile/pirate.dm create mode 100644 tools/UpdatePaths/Scripts/79284_simple_to_basic_pirates.txt diff --git a/_maps/RandomRuins/SpaceRuins/caravanambush.dmm b/_maps/RandomRuins/SpaceRuins/caravanambush.dmm index 3534643bea9..66e681981c7 100644 --- a/_maps/RandomRuins/SpaceRuins/caravanambush.dmm +++ b/_maps/RandomRuins/SpaceRuins/caravanambush.dmm @@ -26,7 +26,7 @@ /area/template_noop) "ah" = ( /obj/structure/lattice/catwalk, -/mob/living/simple_animal/hostile/pirate/ranged/space{ +/mob/living/basic/trooper/pirate/ranged/space{ environment_smash = 0 }, /turf/template_noop, @@ -587,7 +587,7 @@ dir = 4 }, /obj/effect/decal/cleanable/dirt, -/mob/living/simple_animal/hostile/pirate/ranged/space{ +/mob/living/basic/trooper/pirate/ranged/space{ environment_smash = 0 }, /turf/open/floor/iron/airless, @@ -736,7 +736,7 @@ /area/ruin/space/has_grav) "Fr" = ( /obj/effect/decal/cleanable/dirt, -/mob/living/simple_animal/hostile/pirate/ranged/space{ +/mob/living/basic/trooper/pirate/ranged/space{ environment_smash = 0 }, /turf/open/floor/plating/airless, @@ -941,7 +941,7 @@ "Nm" = ( /obj/machinery/atmospherics/components/unary/vent_pump/on, /obj/effect/decal/cleanable/dirt, -/mob/living/simple_animal/hostile/pirate/ranged/space{ +/mob/living/basic/trooper/pirate/ranged/space{ environment_smash = 0 }, /turf/open/floor/iron/airless, diff --git a/_maps/RandomRuins/SpaceRuins/derelict_construction.dmm b/_maps/RandomRuins/SpaceRuins/derelict_construction.dmm index 6eeb3dd3ef3..a8c3607258d 100644 --- a/_maps/RandomRuins/SpaceRuins/derelict_construction.dmm +++ b/_maps/RandomRuins/SpaceRuins/derelict_construction.dmm @@ -31,7 +31,7 @@ /area/ruin/space/has_grav/derelictconstruction) "fa" = ( /obj/structure/lattice, -/mob/living/simple_animal/hostile/pirate/ranged/space, +/mob/living/basic/trooper/pirate/ranged/space, /turf/template_noop, /area/space/nearstation) "gi" = ( @@ -416,7 +416,7 @@ /turf/open/floor/plating, /area/ruin/space/has_grav/derelictconstruction) "Za" = ( -/mob/living/simple_animal/hostile/pirate/melee/space, +/mob/living/basic/trooper/pirate/melee/space, /obj/structure/lattice/catwalk, /turf/template_noop, /area/ruin/space/has_grav/derelictconstruction) diff --git a/_maps/shuttles/ruin_pirate_cutter.dmm b/_maps/shuttles/ruin_pirate_cutter.dmm index 634386c56c2..7dd4be59ba7 100644 --- a/_maps/shuttles/ruin_pirate_cutter.dmm +++ b/_maps/shuttles/ruin_pirate_cutter.dmm @@ -75,7 +75,7 @@ /turf/open/floor/plating, /area/shuttle/ruin/caravan/pirate) "iN" = ( -/mob/living/simple_animal/hostile/pirate/melee{ +/mob/living/basic/trooper/pirate/melee{ environment_smash = 0 }, /turf/open/floor/iron, @@ -139,7 +139,7 @@ pixel_y = -30; req_access = null }, -/mob/living/simple_animal/hostile/pirate/ranged{ +/mob/living/basic/trooper/pirate/ranged{ environment_smash = 0 }, /obj/effect/turf_decal/tile/neutral/fourcorners, @@ -787,7 +787,7 @@ /area/shuttle/ruin/caravan/pirate) "WV" = ( /obj/effect/decal/cleanable/dirt, -/mob/living/simple_animal/hostile/pirate/ranged{ +/mob/living/basic/trooper/pirate/ranged{ environment_smash = 0 }, /turf/open/floor/iron, diff --git a/_maps/virtual_domains/pirates.dmm b/_maps/virtual_domains/pirates.dmm index 9c970f78c37..9868ab8e9b3 100644 --- a/_maps/virtual_domains/pirates.dmm +++ b/_maps/virtual_domains/pirates.dmm @@ -161,7 +161,7 @@ dir = 8 }, /obj/effect/decal/cleanable/dirt/dust, -/mob/living/simple_animal/hostile/pirate/ranged/space, +/mob/living/basic/trooper/pirate/ranged/space, /turf/open/floor/carpet/blue, /area/virtual_domain/powered) "iO" = ( @@ -293,7 +293,7 @@ /area/virtual_domain/powered) "nX" = ( /obj/effect/decal/cleanable/dirt/dust, -/mob/living/simple_animal/hostile/pirate/melee/space, +/mob/living/basic/trooper/pirate/melee/space, /turf/open/floor/wood/parquet, /area/virtual_domain/powered) "oo" = ( @@ -342,7 +342,7 @@ }, /obj/effect/mapping_helpers/burnt_floor, /obj/effect/decal/cleanable/dirt/dust, -/mob/living/simple_animal/hostile/pirate/ranged, +/mob/living/basic/trooper/pirate/ranged, /turf/open/floor/wood, /area/virtual_domain/powered) "qN" = ( @@ -385,7 +385,7 @@ /turf/open/misc/grass, /area/virtual_domain/powered) "to" = ( -/mob/living/simple_animal/hostile/pirate/melee, +/mob/living/basic/trooper/pirate/melee, /turf/open/misc/grass, /area/virtual_domain/powered) "ub" = ( @@ -472,7 +472,7 @@ /turf/open/misc/dirt/jungle, /area/virtual_domain/powered) "yi" = ( -/mob/living/simple_animal/hostile/pirate/melee, +/mob/living/basic/trooper/pirate/melee, /turf/open/misc/beach/sand, /area/virtual_domain/powered) "yq" = ( @@ -481,7 +481,7 @@ /area/virtual_domain/powered) "yw" = ( /obj/effect/mapping_helpers/burnt_floor, -/mob/living/simple_animal/hostile/pirate/ranged, +/mob/living/basic/trooper/pirate/ranged, /obj/structure/chair/wood, /turf/open/floor/wood{ icon_state = "wood_large" @@ -616,7 +616,7 @@ /area/virtual_domain/powered) "Hp" = ( /obj/effect/turf_decal/siding/wood, -/mob/living/simple_animal/hostile/pirate/ranged, +/mob/living/basic/trooper/pirate/ranged, /turf/open/floor/wood, /area/virtual_domain/powered) "HY" = ( diff --git a/code/datums/components/plundering_attacks.dm b/code/datums/components/plundering_attacks.dm new file mode 100644 index 00000000000..f55fa42b071 --- /dev/null +++ b/code/datums/components/plundering_attacks.dm @@ -0,0 +1,54 @@ +/** + * Component that makes basic mobs' melee attacks steal money from the target's ID card. + * Plundered money is stored and dropped on death or removal of the component. + */ +/datum/component/plundering_attacks + /// How many credits do we steal per attack? + var/plunder_amount = 25 + /// How much plunder do we have stored? + var/plunder_stored = 0 + + +/datum/component/plundering_attacks/Initialize( + plunder_amount = 25, +) + . = ..() + if(!isbasicmob(parent)) + return COMPONENT_INCOMPATIBLE + + src.plunder_amount = plunder_amount + +/datum/component/plundering_attacks/RegisterWithParent() + . = ..() + RegisterSignal(parent, COMSIG_HOSTILE_POST_ATTACKINGTARGET, PROC_REF(attempt_plunder)) + RegisterSignal(parent, COMSIG_LIVING_DEATH, PROC_REF(drop_plunder)) + +/datum/component/plundering_attacks/UnregisterFromParent() + . = ..() + UnregisterSignal(parent, list(COMSIG_HOSTILE_POST_ATTACKINGTARGET, COMSIG_LIVING_DEATH)) + drop_plunder() + +/datum/component/plundering_attacks/proc/attempt_plunder(mob/living/attacker, mob/living/carbon/human/target, success) + SIGNAL_HANDLER + if(!istype(target) || !success) + return + var/obj/item/card/id/id_card = target.wear_id?.GetID() + if(isnull(id_card)) + return + var/datum/bank_account/account_to_rob = id_card.registered_account + if(isnull(account_to_rob) || account_to_rob.account_balance == 0) + return + + var/amount_to_steal = plunder_amount + if(account_to_rob.account_balance < plunder_amount) //If there isn't enough, just take what's left + amount_to_steal = account_to_rob.account_balance + plunder_stored += amount_to_steal + account_to_rob.adjust_money(-amount_to_steal) + account_to_rob.bank_card_talk("Transaction confirmed! Transferred [amount_to_steal] credits to \!") + +/datum/component/plundering_attacks/proc/drop_plunder() + SIGNAL_HANDLER + if(plunder_stored == 0) + return + new /obj/item/holochip(get_turf(parent), plunder_stored) + plunder_stored = 0 diff --git a/code/modules/mob/living/basic/trooper/pirate.dm b/code/modules/mob/living/basic/trooper/pirate.dm new file mode 100644 index 00000000000..714fc53856e --- /dev/null +++ b/code/modules/mob/living/basic/trooper/pirate.dm @@ -0,0 +1,89 @@ +/// Pirate trooper subtype +/mob/living/basic/trooper/pirate + name = "Pirate" + desc = "Does what he wants cause a pirate is free." + response_help_continuous = "pushes" + response_help_simple = "push" + speed = 0 + speak_emote = list("yarrs") + faction = list(FACTION_PIRATE) + loot = list(/obj/effect/mob_spawn/corpse/human/pirate) + mob_spawner = /obj/effect/mob_spawn/corpse/human/pirate + + /// The amount of money to steal with a melee attack + var/plunder_credits = 25 + +/mob/living/basic/trooper/pirate/Initialize(mapload) + . = ..() + AddComponent(/datum/component/plundering_attacks, plunder_amount = plunder_credits) + +/mob/living/basic/trooper/pirate/melee + name = "Pirate Swashbuckler" + melee_damage_lower = 30 + melee_damage_upper = 30 + armour_penetration = 35 + attack_verb_continuous = "slashes" + attack_verb_simple = "slash" + attack_sound = 'sound/weapons/blade1.ogg' + attack_vis_effect = ATTACK_EFFECT_SLASH + loot = list(/obj/effect/mob_spawn/corpse/human/pirate/melee) + light_range = 2 + light_power = 2.5 + light_color = COLOR_SOFT_RED + loot = list( + /obj/effect/mob_spawn/corpse/human/pirate/melee, + /obj/item/melee/energy/sword/pirate, + ) + mob_spawner = /obj/effect/mob_spawn/corpse/human/pirate/melee + r_hand = /obj/item/melee/energy/sword/pirate + plunder_credits = 50 //they hit hard so they steal more + +/mob/living/basic/trooper/pirate/melee/space + name = "Space Pirate Swashbuckler" + unsuitable_atmos_damage = 0 + minimum_survivable_temperature = 0 + speed = 1 + loot = list(/obj/effect/mob_spawn/corpse/human/pirate/melee/space) + mob_spawner = /obj/effect/mob_spawn/corpse/human/pirate/melee/space + +/mob/living/basic/trooper/pirate/melee/space/Initialize(mapload) + . = ..() + ADD_TRAIT(src, TRAIT_SPACEWALK, INNATE_TRAIT) + +/mob/living/basic/trooper/pirate/ranged + name = "Pirate Gunner" + loot = list(/obj/effect/mob_spawn/corpse/human/pirate/ranged) + mob_spawner = /obj/effect/mob_spawn/corpse/human/pirate/ranged + r_hand = /obj/item/gun/energy/laser + ai_controller = /datum/ai_controller/basic_controller/trooper/ranged + /// Type of bullet we use + var/casingtype = /obj/item/ammo_casing/energy/laser + /// Sound to play when firing weapon + var/projectilesound = 'sound/weapons/laser.ogg' + /// number of burst shots + var/burst_shots = 2 + /// Time between taking shots + var/ranged_cooldown = 6 SECONDS + +/mob/living/basic/trooper/pirate/ranged/Initialize(mapload) + . = ..() + AddComponent(\ + /datum/component/ranged_attacks,\ + casing_type = casingtype,\ + projectile_sound = projectilesound,\ + cooldown_time = ranged_cooldown,\ + burst_shots = burst_shots,\ + ) + +/mob/living/basic/trooper/pirate/ranged/space + name = "Space Pirate Gunner" + unsuitable_atmos_damage = 0 + minimum_survivable_temperature = 0 + speed = 1 + loot = list(/obj/effect/mob_spawn/corpse/human/pirate/ranged/space) + mob_spawner = /obj/effect/mob_spawn/corpse/human/pirate/ranged/space + r_hand = /obj/item/gun/energy/e_gun/lethal + +/mob/living/basic/trooper/pirate/ranged/space/Initialize(mapload) + . = ..() + ADD_TRAIT(src, TRAIT_SPACEWALK, INNATE_TRAIT) diff --git a/code/modules/mob/living/basic/trooper/syndicate.dm b/code/modules/mob/living/basic/trooper/syndicate.dm index 43242649193..7075e293add 100644 --- a/code/modules/mob/living/basic/trooper/syndicate.dm +++ b/code/modules/mob/living/basic/trooper/syndicate.dm @@ -3,8 +3,6 @@ name = "Syndicate Operative" desc = "Death to Nanotrasen." speed = 1.1 - melee_damage_lower = 10 - melee_damage_upper = 10 faction = list(ROLE_SYNDICATE) loot = list(/obj/effect/mob_spawn/corpse/human/syndicatesoldier) mob_spawner = /obj/effect/mob_spawn/corpse/human/syndicatesoldier diff --git a/code/modules/mob/living/simple_animal/hostile/pirate.dm b/code/modules/mob/living/simple_animal/hostile/pirate.dm deleted file mode 100644 index 24503f89bfd..00000000000 --- a/code/modules/mob/living/simple_animal/hostile/pirate.dm +++ /dev/null @@ -1,91 +0,0 @@ -/mob/living/simple_animal/hostile/pirate - name = "Pirate" - desc = "Does what he wants cause a pirate is free." - icon = 'icons/mob/simple/simple_human.dmi' - mob_biotypes = MOB_ORGANIC|MOB_HUMANOID - sentience_type = SENTIENCE_HUMANOID - speak_chance = 0 - turns_per_move = 5 - response_help_continuous = "pushes" - response_help_simple = "push" - speed = 0 - maxHealth = 100 - health = 100 - harm_intent_damage = 5 - melee_damage_lower = 10 - melee_damage_upper = 10 - attack_verb_continuous = "punches" - attack_verb_simple = "punch" - attack_sound = 'sound/weapons/punch1.ogg' - combat_mode = TRUE - atmos_requirements = list("min_oxy" = 5, "max_oxy" = 0, "min_plas" = 0, "max_plas" = 1, "min_co2" = 0, "max_co2" = 5, "min_n2" = 0, "max_n2" = 0) - unsuitable_atmos_damage = 7.5 - speak_emote = list("yarrs") - loot = list(/obj/effect/mob_spawn/corpse/human/pirate) - del_on_death = TRUE - faction = list(FACTION_PIRATE) - /// Path of the mob spawner we base the mob's visuals off of. - var/mob_spawner = /obj/effect/mob_spawn/corpse/human/pirate - /// Path of the held item we give to the mob's visuals. - var/held_item - -/mob/living/simple_animal/hostile/pirate/Initialize(mapload) - . = ..() - apply_dynamic_human_appearance(src, mob_spawn_path = mob_spawner, r_hand = held_item) - -/mob/living/simple_animal/hostile/pirate/melee - name = "Pirate Swashbuckler" - melee_damage_lower = 30 - melee_damage_upper = 30 - armour_penetration = 35 - attack_verb_continuous = "slashes" - attack_verb_simple = "slash" - attack_sound = 'sound/weapons/blade1.ogg' - attack_vis_effect = ATTACK_EFFECT_SLASH - loot = list(/obj/effect/mob_spawn/corpse/human/pirate/melee) - light_range = 2 - light_power = 2.5 - light_color = COLOR_SOFT_RED - footstep_type = FOOTSTEP_MOB_SHOE - loot = list( - /obj/effect/mob_spawn/corpse/human/pirate/melee, - /obj/item/melee/energy/sword/pirate, - ) - mob_spawner = /obj/effect/mob_spawn/corpse/human/pirate/melee - held_item = /obj/item/melee/energy/sword/pirate - -/mob/living/simple_animal/hostile/pirate/melee/space - name = "Space Pirate Swashbuckler" - atmos_requirements = list("min_oxy" = 0, "max_oxy" = 0, "min_plas" = 0, "max_plas" = 0, "min_co2" = 0, "max_co2" = 0, "min_n2" = 0, "max_n2" = 0) - minbodytemp = 0 - speed = 1 - mob_spawner = /obj/effect/mob_spawn/corpse/human/pirate/melee/space - -/mob/living/simple_animal/hostile/pirate/melee/space/Initialize(mapload) - . = ..() - ADD_TRAIT(src, TRAIT_SPACEWALK, INNATE_TRAIT) - -/mob/living/simple_animal/hostile/pirate/ranged - name = "Pirate Gunner" - projectilesound = 'sound/weapons/laser.ogg' - ranged = 1 - rapid = 2 - rapid_fire_delay = 6 - retreat_distance = 5 - minimum_distance = 5 - projectiletype = /obj/projectile/beam/laser - loot = list(/obj/effect/mob_spawn/corpse/human/pirate/ranged) - mob_spawner = /obj/effect/mob_spawn/corpse/human/pirate/ranged - held_item = /obj/item/gun/energy/laser - -/mob/living/simple_animal/hostile/pirate/ranged/space - name = "Space Pirate Gunner" - atmos_requirements = list("min_oxy" = 0, "max_oxy" = 0, "min_plas" = 0, "max_plas" = 0, "min_co2" = 0, "max_co2" = 0, "min_n2" = 0, "max_n2" = 0) - minbodytemp = 0 - speed = 1 - mob_spawner = /obj/effect/mob_spawn/corpse/human/pirate/ranged/space - held_item = /obj/item/gun/energy/e_gun/lethal - -/mob/living/simple_animal/hostile/pirate/ranged/space/Initialize(mapload) - . = ..() - ADD_TRAIT(src, TRAIT_SPACEWALK, INNATE_TRAIT) diff --git a/code/modules/unit_tests/simple_animal_freeze.dm b/code/modules/unit_tests/simple_animal_freeze.dm index 5fce21d244a..b6c8c468f19 100644 --- a/code/modules/unit_tests/simple_animal_freeze.dm +++ b/code/modules/unit_tests/simple_animal_freeze.dm @@ -120,11 +120,6 @@ /mob/living/simple_animal/hostile/ooze, /mob/living/simple_animal/hostile/ooze/gelatinous, /mob/living/simple_animal/hostile/ooze/grapes, - /mob/living/simple_animal/hostile/pirate, - /mob/living/simple_animal/hostile/pirate/melee, - /mob/living/simple_animal/hostile/pirate/melee/space, - /mob/living/simple_animal/hostile/pirate/ranged, - /mob/living/simple_animal/hostile/pirate/ranged/space, /mob/living/simple_animal/hostile/retaliate, /mob/living/simple_animal/hostile/retaliate/goose, /mob/living/simple_animal/hostile/retaliate/goose/vomit, diff --git a/tgstation.dme b/tgstation.dme index 48feb68f0fa..b18f53b251e 100644 --- a/tgstation.dme +++ b/tgstation.dme @@ -1068,6 +1068,7 @@ #include "code\datums\components\pellet_cloud.dm" #include "code\datums\components\phylactery.dm" #include "code\datums\components\pinata.dm" +#include "code\datums\components\plundering_attacks.dm" #include "code\datums\components\pricetag.dm" #include "code\datums\components\punchcooldown.dm" #include "code\datums\components\puzzgrid.dm" @@ -4571,6 +4572,7 @@ #include "code\modules\mob\living\basic\space_fauna\wumborian_fugu\wumborian_ai.dm" #include "code\modules\mob\living\basic\space_fauna\wumborian_fugu\wumborian_fugu.dm" #include "code\modules\mob\living\basic\trooper\nanotrasen.dm" +#include "code\modules\mob\living\basic\trooper\pirate.dm" #include "code\modules\mob\living\basic\trooper\russian.dm" #include "code\modules\mob\living\basic\trooper\syndicate.dm" #include "code\modules\mob\living\basic\trooper\trooper.dm" @@ -4767,7 +4769,6 @@ #include "code\modules\mob\living\simple_animal\hostile\illusion.dm" #include "code\modules\mob\living\simple_animal\hostile\mimic.dm" #include "code\modules\mob\living\simple_animal\hostile\ooze.dm" -#include "code\modules\mob\living\simple_animal\hostile\pirate.dm" #include "code\modules\mob\living\simple_animal\hostile\vatbeast.dm" #include "code\modules\mob\living\simple_animal\hostile\wizard.dm" #include "code\modules\mob\living\simple_animal\hostile\zombie.dm" diff --git a/tools/UpdatePaths/Scripts/79284_simple_to_basic_pirates.txt b/tools/UpdatePaths/Scripts/79284_simple_to_basic_pirates.txt new file mode 100644 index 00000000000..b642fc4278f --- /dev/null +++ b/tools/UpdatePaths/Scripts/79284_simple_to_basic_pirates.txt @@ -0,0 +1 @@ +/mob/living/simple_animal/hostile/pirate/@SUBTYPES : /mob/living/basic/trooper/pirate/@SUBTYPES{@OLD} \ No newline at end of file