mirror of
https://github.com/Bubberstation/Bubberstation.git
synced 2026-08-27 23:27:34 +01:00
[MIRROR] Basic Mob Carp Part VIII: Basic Mob Carp [MDB IGNORE] (#18344)
* Basic Mob Carp Part VIII: Basic Mob Carp * maps * missed killing main carp file * shorki and ocean biomes * shorki 2: pet-a-boogaloo Co-authored-by: Jacquerel <hnevard@gmail.com> Co-authored-by: tastyfish <crazychris32@gmail.com>
This commit is contained in:
co-authored by
Jacquerel
tastyfish
parent
381bbef2f8
commit
7ee524f748
@@ -63,7 +63,7 @@
|
||||
if(!food_types)
|
||||
food_types = src.food_types.Copy()
|
||||
AddComponent(/datum/component/tameable, food_types = food_types, tame_chance = 25, bonus_tame_chance = 15, after_tame = CALLBACK(src, PROC_REF(tamed)))
|
||||
AddElement(/datum/element/basic_eating, 10, food_types)
|
||||
AddElement(/datum/element/basic_eating, 10, 0, null, food_types)
|
||||
|
||||
/mob/living/basic/cow/proc/tamed(mob/living/tamer)
|
||||
buckle_lying = 0
|
||||
|
||||
@@ -34,7 +34,7 @@
|
||||
var/static/list/food_types
|
||||
if(!food_types)
|
||||
food_types = src.food_types.Copy()
|
||||
AddElement(/datum/element/basic_eating, 10, food_types)
|
||||
AddElement(/datum/element/basic_eating, 10, 0, null, food_types)
|
||||
AddComponent(/datum/component/tameable, food_types = food_types, tame_chance = 25, bonus_tame_chance = 15, after_tame = CALLBACK(src, PROC_REF(tamed)))
|
||||
|
||||
/mob/living/basic/cow/moonicorn/tamed(mob/living/tamer)
|
||||
|
||||
@@ -0,0 +1,215 @@
|
||||
/**
|
||||
* ## Space Carp
|
||||
*
|
||||
* A migratory dwarf fortress reference who swim through space and sometimes bump into the space station.
|
||||
* Can be created in dehydrated form by traitors, and are also summoned through rifts by space dragons.
|
||||
*
|
||||
* Begin regenerating their health after a short time without taking any damage, and will try to run away to do this if they get hurt.
|
||||
* Lethally attracted to loose plastic.
|
||||
*
|
||||
* Tameable by feeding them meat, and can follow basic instructions. Rideable.
|
||||
* Owned as a pet both by the HoS (sometimes) and also the Nuclear Operatives.
|
||||
*/
|
||||
/mob/living/basic/carp
|
||||
name = "space carp"
|
||||
desc = "A ferocious, fang-bearing creature that resembles a fish."
|
||||
icon = 'icons/mob/simple/carp.dmi'
|
||||
icon_state = "base"
|
||||
icon_living = "base"
|
||||
icon_dead = "base_dead"
|
||||
icon_gib = "carp_gib"
|
||||
gold_core_spawnable = HOSTILE_SPAWN
|
||||
mob_biotypes = MOB_ORGANIC | MOB_BEAST
|
||||
movement_type = FLYING
|
||||
health = 25
|
||||
maxHealth = 25
|
||||
pressure_resistance = 200
|
||||
combat_mode = TRUE
|
||||
obj_damage = 50
|
||||
melee_damage_lower = 20
|
||||
melee_damage_upper = 20
|
||||
attack_sound = 'sound/weapons/bite.ogg'
|
||||
attack_vis_effect = ATTACK_EFFECT_BITE
|
||||
attack_verb_continuous = "bites"
|
||||
attack_verb_simple = "bite"
|
||||
response_help_continuous = "pets"
|
||||
response_help_simple = "pet"
|
||||
response_disarm_continuous = "gently pushes aside"
|
||||
response_disarm_simple = "gently push aside"
|
||||
faction = list("carp")
|
||||
butcher_results = list(/obj/item/food/fishmeat/carp = 2, /obj/item/stack/sheet/animalhide/carp = 1)
|
||||
greyscale_config = /datum/greyscale_config/carp
|
||||
ai_controller = /datum/ai_controller/basic_controller/carp
|
||||
|
||||
/// Cytology cells you can swab from this creature
|
||||
var/cell_line = CELL_LINE_TABLE_CARP
|
||||
/// What colour is our 'healing' outline?
|
||||
var/regenerate_colour = COLOR_PALE_GREEN
|
||||
/// Information to apply when treating this carp as a vehicle
|
||||
var/ridable_data = /datum/component/riding/creature/carp
|
||||
/// Commands you can give this carp once it is tamed, not static because subtypes can modify it
|
||||
var/tamed_commands = list(
|
||||
/datum/pet_command/idle,
|
||||
/datum/pet_command/free,
|
||||
/datum/pet_command/follow,
|
||||
/datum/pet_command/point_targetting/attack/carp
|
||||
)
|
||||
/// Carp want to eat raw meat
|
||||
var/static/list/desired_food = list(/obj/item/food/meat/slab, /obj/item/food/meat/rawcutlet)
|
||||
/// Carp want to eat delicious six pack plastic rings
|
||||
var/static/list/desired_trash = list(/obj/item/storage/cans)
|
||||
/// Weighted list of colours a carp can be
|
||||
/// Weighted list of usual carp colors
|
||||
var/static/list/carp_colors = list(
|
||||
COLOR_CARP_PURPLE = 7,
|
||||
COLOR_CARP_PINK = 7,
|
||||
COLOR_CARP_GREEN = 7,
|
||||
COLOR_CARP_GRAPE = 7,
|
||||
COLOR_CARP_SWAMP = 7,
|
||||
COLOR_CARP_TURQUOISE = 7,
|
||||
COLOR_CARP_BROWN = 7,
|
||||
COLOR_CARP_TEAL = 7,
|
||||
COLOR_CARP_LIGHT_BLUE = 7,
|
||||
COLOR_CARP_RUSTY = 7,
|
||||
COLOR_CARP_RED = 7,
|
||||
COLOR_CARP_YELLOW = 7,
|
||||
COLOR_CARP_BLUE = 7,
|
||||
COLOR_CARP_PALE_GREEN = 7,
|
||||
COLOR_CARP_SILVER = 1, // The rare silver carp
|
||||
)
|
||||
|
||||
/mob/living/basic/carp/Initialize(mapload, mob/tamer)
|
||||
. = ..()
|
||||
apply_colour()
|
||||
ADD_TRAIT(src, TRAIT_HEALS_FROM_CARP_RIFTS, INNATE_TRAIT)
|
||||
ADD_TRAIT(src, TRAIT_SPACEWALK, INNATE_TRAIT)
|
||||
|
||||
if (cell_line)
|
||||
AddElement(/datum/element/swabable, cell_line, CELL_VIRUS_TABLE_GENERIC_MOB, 1, 5)
|
||||
AddElement(/datum/element/simple_flying)
|
||||
AddElement(/datum/element/ai_flee_while_injured)
|
||||
setup_eating()
|
||||
|
||||
AddComponent(/datum/component/regenerator, outline_colour = regenerate_colour)
|
||||
if (tamer)
|
||||
befriend(tamer)
|
||||
on_tamed(tamer, FALSE)
|
||||
else
|
||||
AddComponent(/datum/component/tameable, food_types = list(/obj/item/food/meat), tame_chance = 10, bonus_tame_chance = 5, after_tame = CALLBACK(src, PROC_REF(on_tamed)))
|
||||
|
||||
/// Tell the elements and the blackboard what food we want to eat
|
||||
/mob/living/basic/carp/proc/setup_eating()
|
||||
AddElement(/datum/element/basic_eating, 10, 0, null, desired_food)
|
||||
AddElement(/datum/element/basic_eating, 0, 10, BRUTE, desired_trash) // We are killing our planet
|
||||
ai_controller.blackboard[BB_BASIC_FOODS] = desired_food + desired_trash
|
||||
|
||||
/// Set a random colour on the carp, override to do something else
|
||||
/mob/living/basic/carp/proc/apply_colour()
|
||||
if (!greyscale_config)
|
||||
return
|
||||
set_greyscale(colors = list(pick_weight(carp_colors)))
|
||||
|
||||
/// Called when another mob has forged a bond of friendship with this one, passed the taming mob as 'tamer'
|
||||
/mob/living/basic/carp/proc/on_tamed(mob/tamer, feedback = TRUE)
|
||||
buckle_lying = 0
|
||||
AddElement(/datum/element/ridable, ridable_data)
|
||||
AddComponent(/datum/component/obeys_commands, tamed_commands)
|
||||
if (!feedback)
|
||||
return
|
||||
spin(spintime = 10, speed = 1)
|
||||
visible_message("[src] spins in a circle as it seems to bond with [tamer].")
|
||||
|
||||
/**
|
||||
* Holographic carp from the holodeck
|
||||
*/
|
||||
/mob/living/basic/carp/holographic
|
||||
icon_state = "holocarp"
|
||||
icon_living = "holocarp"
|
||||
gold_core_spawnable = NO_SPAWN
|
||||
greyscale_config = NONE
|
||||
basic_mob_flags = DEL_ON_DEATH
|
||||
cell_line = NONE
|
||||
regenerate_colour = "#ffffff"
|
||||
|
||||
/// Holocarp don't eat food
|
||||
/mob/living/basic/carp/holographic/setup_eating()
|
||||
return FALSE
|
||||
|
||||
/**
|
||||
* Pet carp, abstract carp which just holds some shared properties.
|
||||
*/
|
||||
/mob/living/basic/carp/pet
|
||||
speak_emote = list("squeaks")
|
||||
gold_core_spawnable = NO_SPAWN
|
||||
gender = FEMALE // Both current existing pet carp are female but you can remove this if someone else gets a male one?
|
||||
ai_controller = /datum/ai_controller/basic_controller/carp/pet
|
||||
|
||||
/mob/living/basic/carp/pet/Initialize(mapload)
|
||||
. = ..()
|
||||
AddElement(/datum/element/ai_retaliate)
|
||||
AddElement(/datum/element/pet_bonus, "bloops happily!")
|
||||
|
||||
/**
|
||||
* Lia - Sometimes the pet of the Head of Security.
|
||||
* Has a lot more health than a normal carp because she's meant to be a mildly more threatening pet to have to assassinate than an aging corgi.
|
||||
*/
|
||||
/mob/living/basic/carp/pet/lia
|
||||
name = "Lia"
|
||||
real_name = "Lia"
|
||||
desc = "A failed experiment of Nanotrasen to create weaponised carp technology. This less than intimidating carp now serves as the Head of Security's pet."
|
||||
faction = list("neutral")
|
||||
maxHealth = 200
|
||||
health = 200
|
||||
icon_dead = "magicarp_dead"
|
||||
icon_gib = "magicarp_gib"
|
||||
icon_living = "magicarp"
|
||||
icon_state = "magicarp"
|
||||
greyscale_config = NONE
|
||||
|
||||
/// Boosted chance for Cayenne to be silver
|
||||
#define RARE_CAYENNE_CHANCE 10
|
||||
|
||||
/**
|
||||
* Cayenne - Loyal member of the nuclear operatives.
|
||||
* Spawns in the nuke op shuttle, can be made sapient if they want to do that for some reason.
|
||||
* Is very talented and also capable of holding the nuclear disk.
|
||||
*/
|
||||
/mob/living/basic/carp/pet/cayenne
|
||||
name = "Cayenne"
|
||||
real_name = "Cayenne"
|
||||
desc = "A failed Syndicate experiment in weaponized space carp technology, it now serves as a lovable mascot."
|
||||
faction = list(ROLE_SYNDICATE)
|
||||
/// Overlay to apply to display the disk
|
||||
var/mutable_appearance/disk_overlay
|
||||
/// Overlay to apply over the disk so it looks like cayenne is holding it
|
||||
var/mutable_appearance/mouth_overlay
|
||||
|
||||
/mob/living/basic/carp/pet/cayenne/Initialize(mapload)
|
||||
. = ..()
|
||||
var/datum/callback/got_disk = CALLBACK(src, PROC_REF(got_disk))
|
||||
var/datum/callback/display_disk = CALLBACK(src, PROC_REF(display_disk))
|
||||
AddComponent(/datum/component/nuclear_bomb_operator, got_disk, display_disk)
|
||||
|
||||
/mob/living/basic/carp/pet/cayenne/apply_colour()
|
||||
if (prob(RARE_CAYENNE_CHANCE))
|
||||
set_greyscale(colors = list(COLOR_CARP_SILVER))
|
||||
else
|
||||
return ..()
|
||||
|
||||
/// She did it! Treats for Cayenne!
|
||||
/mob/living/basic/carp/pet/cayenne/proc/got_disk(obj/item/disk/nuclear/disky)
|
||||
if (disky.fake) // Never mind she didn't do it
|
||||
return
|
||||
client.give_award(/datum/award/achievement/misc/cayenne_disk, src)
|
||||
|
||||
/// Adds an overlay to show the disk on Cayenne
|
||||
/mob/living/basic/carp/pet/cayenne/proc/display_disk(list/new_overlays)
|
||||
if (!mouth_overlay)
|
||||
mouth_overlay = mutable_appearance(SSgreyscale.GetColoredIconByType(/datum/greyscale_config/carp/disk_mouth, greyscale_colors), "disk_mouth")
|
||||
new_overlays += mouth_overlay
|
||||
|
||||
if (!disk_overlay)
|
||||
disk_overlay = mutable_appearance('icons/mob/simple/carp.dmi', "disk_overlay")
|
||||
new_overlays += disk_overlay
|
||||
|
||||
#undef RARE_CAYENNE_CHANCE
|
||||
@@ -0,0 +1,29 @@
|
||||
/**
|
||||
* # Magicarp Bolt
|
||||
* Holder ability simply for "firing a projectile with a cooldown".
|
||||
* Probably won't do anything if assigned via VV unless you also VV in a projectile for it.
|
||||
*/
|
||||
/datum/action/cooldown/mob_cooldown/projectile_attack/magicarp_bolt
|
||||
name = "Magicarp Blast"
|
||||
desc = "Unleash a bolt of magical force at a target you click on."
|
||||
button_icon = 'icons/obj/weapons/guns/projectiles.dmi'
|
||||
button_icon_state = "arcane_barrage"
|
||||
cooldown_time = 5 SECONDS
|
||||
projectile_sound = 'sound/weapons/emitter.ogg'
|
||||
melee_cooldown_time = 0 SECONDS // Without this they become extremely hesitant to bite anyone ever
|
||||
shared_cooldown = MOB_SHARED_COOLDOWN_2
|
||||
|
||||
/datum/action/cooldown/mob_cooldown/projectile_attack/magicarp_bolt/chaos/attack_sequence(mob/living/firer, atom/target)
|
||||
playsound(get_turf(firer), projectile_sound, 100, vary = TRUE)
|
||||
return ..()
|
||||
|
||||
/// Chaos variant picks one from a list
|
||||
/datum/action/cooldown/mob_cooldown/projectile_attack/magicarp_bolt/chaos
|
||||
/// List of things we can cast
|
||||
var/list/permitted_projectiles = list()
|
||||
|
||||
/datum/action/cooldown/mob_cooldown/projectile_attack/magicarp_bolt/chaos/attack_sequence(mob/living/firer, atom/target)
|
||||
if (!length(permitted_projectiles))
|
||||
return
|
||||
projectile_type = pick(permitted_projectiles)
|
||||
return ..()
|
||||
@@ -0,0 +1,74 @@
|
||||
#define MAGICARP_SPELL_TARGET_SEEK_RANGE 4
|
||||
|
||||
/datum/pet_command/point_targetting/attack/carp
|
||||
attack_behaviour = /datum/ai_behavior/basic_melee_attack/carp
|
||||
|
||||
/datum/pet_command/point_targetting/use_ability/magicarp
|
||||
pet_ability_key = BB_MAGICARP_SPELL
|
||||
|
||||
/datum/ai_planning_subtree/basic_melee_attack_subtree/carp
|
||||
melee_attack_behavior = /datum/ai_behavior/basic_melee_attack/carp
|
||||
|
||||
/datum/ai_behavior/basic_melee_attack/carp
|
||||
action_cooldown = 1.5 SECONDS
|
||||
|
||||
/datum/ai_planning_subtree/attack_obstacle_in_path/carp
|
||||
attack_behaviour = /datum/ai_behavior/attack_obstructions/carp
|
||||
|
||||
/datum/ai_behavior/attack_obstructions/carp
|
||||
action_cooldown = 1.5 SECONDS
|
||||
|
||||
/// As basic attack tree but interrupt if your health gets low or if your spell is off cooldown
|
||||
/datum/ai_planning_subtree/basic_melee_attack_subtree/magicarp
|
||||
melee_attack_behavior = /datum/ai_behavior/basic_melee_attack/carp/magic
|
||||
|
||||
/// Interrupt your attack chain if: you have a spell, it's not on cooldown, and it has a target
|
||||
/datum/ai_behavior/basic_melee_attack/carp/magic
|
||||
|
||||
/datum/ai_behavior/basic_melee_attack/carp/magic/perform(delta_time, datum/ai_controller/controller, target_key, targetting_datum_key, hiding_location_key, health_ratio_key)
|
||||
var/datum/action/cooldown/using_action = controller.blackboard[BB_MAGICARP_SPELL]
|
||||
if (QDELETED(using_action))
|
||||
return ..()
|
||||
if (!controller.blackboard[BB_MAGICARP_SPELL_SPECIAL_TARGETTING] && using_action.IsAvailable())
|
||||
finish_action(controller, succeeded = FALSE)
|
||||
return
|
||||
return ..()
|
||||
|
||||
/**
|
||||
* Find a target for the magicarp's spell
|
||||
* This gets weird because different spells want different targetting
|
||||
* but I didn't want a new ai controller for every different spell
|
||||
*/
|
||||
/datum/ai_planning_subtree/find_nearest_magicarp_spell_target
|
||||
|
||||
/datum/ai_planning_subtree/find_nearest_magicarp_spell_target/SelectBehaviors(datum/ai_controller/controller, delta_time)
|
||||
var/datum/action/cooldown/using_action = controller.blackboard[BB_MAGICARP_SPELL]
|
||||
if (QDELETED(using_action))
|
||||
return
|
||||
if (!using_action.IsAvailable())
|
||||
return
|
||||
|
||||
var/spell_targetting = controller.blackboard[BB_MAGICARP_SPELL_SPECIAL_TARGETTING]
|
||||
if (!spell_targetting)
|
||||
controller.queue_behavior(/datum/ai_behavior/find_potential_targets/nearest/magicarp, BB_MAGICARP_SPELL_TARGET, BB_TARGETTING_DATUM, BB_BASIC_MOB_CURRENT_TARGET_HIDING_LOCATION)
|
||||
return
|
||||
|
||||
switch(spell_targetting)
|
||||
if (MAGICARP_SPELL_CORPSES)
|
||||
controller.queue_behavior(/datum/ai_behavior/find_and_set/friendly_corpses, BB_MAGICARP_SPELL_TARGET, MAGICARP_SPELL_TARGET_SEEK_RANGE)
|
||||
return
|
||||
if (MAGICARP_SPELL_OBJECTS)
|
||||
controller.queue_behavior(/datum/ai_behavior/find_and_set/animatable, BB_MAGICARP_SPELL_TARGET, MAGICARP_SPELL_TARGET_SEEK_RANGE)
|
||||
return
|
||||
if (MAGICARP_SPELL_WALLS)
|
||||
controller.queue_behavior(/datum/ai_behavior/find_and_set/nearest_wall, BB_MAGICARP_SPELL_TARGET, MAGICARP_SPELL_TARGET_SEEK_RANGE)
|
||||
return
|
||||
|
||||
/// This subtype only exists because if you queue multiple of the same action with different arguments it deletes their stored arguments
|
||||
/datum/ai_behavior/find_potential_targets/nearest/magicarp
|
||||
|
||||
/// Then use it on that target
|
||||
/datum/ai_planning_subtree/targetted_mob_ability/magicarp
|
||||
ability_key = BB_MAGICARP_SPELL
|
||||
target_key = BB_MAGICARP_SPELL_TARGET
|
||||
use_ability_behaviour = /datum/ai_behavior/try_mob_ability/and_clear_target
|
||||
@@ -0,0 +1,62 @@
|
||||
/**
|
||||
* AI controller for carp
|
||||
* Expected flow is:
|
||||
* * If health is low, mark that we want to run away.
|
||||
* * If we want to run away, find nearest target and run out of view of it.
|
||||
* * Look for anything we want to eat in the area and target it.
|
||||
* * If we don't have a target already, find something to attack.
|
||||
* * Go and attack our target (which might be food, or might be a mob).
|
||||
*/
|
||||
/datum/ai_controller/basic_controller/carp
|
||||
blackboard = list(
|
||||
BB_TARGETTING_DATUM = new /datum/targetting_datum/basic/allow_items(),
|
||||
BB_PET_TARGETTING_DATUM = new /datum/targetting_datum/not_friends()
|
||||
)
|
||||
|
||||
ai_movement = /datum/ai_movement/basic_avoidance
|
||||
idle_behavior = /datum/idle_behavior/idle_random_walk
|
||||
planning_subtrees = list(
|
||||
/datum/ai_planning_subtree/pet_planning,
|
||||
/datum/ai_planning_subtree/simple_find_nearest_target_to_flee,
|
||||
/datum/ai_planning_subtree/flee_target,
|
||||
/datum/ai_planning_subtree/find_food,
|
||||
/datum/ai_planning_subtree/simple_find_target,
|
||||
/datum/ai_planning_subtree/attack_obstacle_in_path/carp,
|
||||
/datum/ai_planning_subtree/basic_melee_attack_subtree/carp,
|
||||
)
|
||||
|
||||
/**
|
||||
* Carp which bites back, but doesn't look for targets.
|
||||
* 'Not hunting targets' includes food (and can rings), because they have been well trained.
|
||||
*/
|
||||
/datum/ai_controller/basic_controller/carp/pet
|
||||
blackboard = list(
|
||||
BB_TARGETTING_DATUM = new /datum/targetting_datum/basic/ignore_faction(),
|
||||
BB_PET_TARGETTING_DATUM = new /datum/targetting_datum/not_friends()
|
||||
)
|
||||
ai_traits = STOP_MOVING_WHEN_PULLED
|
||||
planning_subtrees = list(
|
||||
/datum/ai_planning_subtree/pet_planning,
|
||||
/datum/ai_planning_subtree/find_nearest_thing_which_attacked_me_to_flee,
|
||||
/datum/ai_planning_subtree/flee_target,
|
||||
/datum/ai_planning_subtree/target_retaliate,
|
||||
/datum/ai_planning_subtree/attack_obstacle_in_path/carp,
|
||||
/datum/ai_planning_subtree/basic_melee_attack_subtree/carp,
|
||||
)
|
||||
|
||||
/**
|
||||
* AI for carp with a spell.
|
||||
* Flow is basically the same as regular carp, except it will try and cast a spell at its target whenever possible and not fleeing.
|
||||
*/
|
||||
/datum/ai_controller/basic_controller/carp/ranged
|
||||
planning_subtrees = list(
|
||||
/datum/ai_planning_subtree/pet_planning,
|
||||
/datum/ai_planning_subtree/simple_find_nearest_target_to_flee,
|
||||
/datum/ai_planning_subtree/flee_target,
|
||||
/datum/ai_planning_subtree/find_food,
|
||||
/datum/ai_planning_subtree/find_nearest_magicarp_spell_target,
|
||||
/datum/ai_planning_subtree/targetted_mob_ability/magicarp,
|
||||
/datum/ai_planning_subtree/simple_find_target,
|
||||
/datum/ai_planning_subtree/attack_obstacle_in_path/carp,
|
||||
/datum/ai_planning_subtree/basic_melee_attack_subtree/magicarp,
|
||||
)
|
||||
@@ -0,0 +1,136 @@
|
||||
/// A list of spells magicarp can use and a corresponding name prefix to apply
|
||||
GLOBAL_LIST_INIT(magicarp_spell_types, list(
|
||||
/obj/projectile/magic/animate = "dancing",
|
||||
/obj/projectile/magic/arcane_barrage = "arcane",
|
||||
/obj/projectile/magic/change = "transforming",
|
||||
/obj/projectile/magic/death = "grim",
|
||||
/obj/projectile/magic/door = "unbarred",
|
||||
/obj/projectile/magic/fireball = "blazing",
|
||||
/obj/projectile/magic/resurrection = "vital",
|
||||
/obj/projectile/magic/spellblade = "vorpal",
|
||||
/obj/projectile/magic/teleport = "warping",
|
||||
/obj/projectile/magic/babel = "babbling",
|
||||
))
|
||||
|
||||
/// A reduced list of spells for magicarp spawned in xenobiology, less disruptive
|
||||
GLOBAL_LIST_INIT(xenobiology_magicarp_spell_types, list(
|
||||
/obj/projectile/magic/animate = "dancing",
|
||||
/obj/projectile/magic/teleport = "warping",
|
||||
/obj/projectile/magic/door = "unbarred",
|
||||
/obj/projectile/magic/fireball = "blazing",
|
||||
/obj/projectile/magic/spellblade = "vorpal",
|
||||
/obj/projectile/magic/arcane_barrage = "arcane",
|
||||
))
|
||||
|
||||
/// Associative list of magicarp spells to colours, expand this list if you expand the other lists
|
||||
GLOBAL_LIST_INIT(magicarp_spell_colours, list(
|
||||
/obj/projectile/magic/animate = COLOR_CARP_RUSTY,
|
||||
/obj/projectile/magic/arcane_barrage = COLOR_CARP_PURPLE,
|
||||
/obj/projectile/magic/change = COLOR_CARP_PINK,
|
||||
/obj/projectile/magic/death = COLOR_CARP_DARK_BLUE,
|
||||
/obj/projectile/magic/door = COLOR_CARP_GREEN,
|
||||
/obj/projectile/magic/fireball = COLOR_CARP_RED,
|
||||
/obj/projectile/magic/resurrection = COLOR_CARP_PALE_GREEN,
|
||||
/obj/projectile/magic/spellblade = COLOR_CARP_SILVER,
|
||||
/obj/projectile/magic/teleport = COLOR_CARP_GRAPE,
|
||||
/obj/projectile/magic/babel = COLOR_CARP_BROWN,
|
||||
))
|
||||
|
||||
/**
|
||||
* # Magicarp
|
||||
*
|
||||
* Carp who can cast spells!
|
||||
* Mostly created via wizard event or transformation.
|
||||
* Come in 'does one thing' and 'does random things' varieties.
|
||||
*/
|
||||
/mob/living/basic/carp/magic
|
||||
name = "magicarp"
|
||||
desc = "50% magic, 50% carp, 100% horrible."
|
||||
icon_gib = "magicarp_gib"
|
||||
maxHealth = 50
|
||||
health = 50
|
||||
gold_core_spawnable = NO_SPAWN
|
||||
greyscale_config = /datum/greyscale_config/carp_magic
|
||||
ai_controller = /datum/ai_controller/basic_controller/carp/ranged
|
||||
tamed_commands = list(
|
||||
/datum/pet_command/idle,
|
||||
/datum/pet_command/free,
|
||||
/datum/pet_command/follow,
|
||||
/datum/pet_command/point_targetting/attack/carp,
|
||||
/datum/pet_command/point_targetting/use_ability/magicarp,
|
||||
)
|
||||
/// List of all projectiles we can fire.
|
||||
/// Non-static, because subtypes can have their own lists.
|
||||
var/list/allowed_projectile_types
|
||||
/// Our magic attack
|
||||
var/datum/action/cooldown/mob_cooldown/projectile_attack/magicarp_bolt/spell
|
||||
|
||||
/mob/living/basic/carp/magic/Initialize(mapload)
|
||||
. = ..()
|
||||
allowed_projectile_types = spell_list()
|
||||
assign_spell()
|
||||
|
||||
/// Returns the list of spells we are allowed to cast
|
||||
/mob/living/basic/carp/magic/proc/spell_list()
|
||||
return GLOB.magicarp_spell_types
|
||||
|
||||
/// Updates name based on chosen spell
|
||||
/mob/living/basic/carp/magic/proc/assign_spell()
|
||||
var/obj/projectile/spell_type = pick(allowed_projectile_types)
|
||||
name = "[GLOB.magicarp_spell_types[spell_type]] [name]"
|
||||
set_greyscale(colors = list(GLOB.magicarp_spell_colours[spell_type]))
|
||||
|
||||
spell = new (src)
|
||||
spell.projectile_type = spell_type
|
||||
spell.button_icon_state = initial(spell_type.icon_state)
|
||||
spell.Grant(src)
|
||||
ai_controller.blackboard[BB_MAGICARP_SPELL] = spell
|
||||
assign_spell_ai(spell_type)
|
||||
|
||||
/// If you have certain spells, use a different targetting datum
|
||||
/mob/living/basic/carp/magic/proc/assign_spell_ai(spell_type)
|
||||
var/static/list/spell_special_targetting = list(
|
||||
/obj/projectile/magic/animate = MAGICARP_SPELL_OBJECTS,
|
||||
/obj/projectile/magic/door = MAGICARP_SPELL_WALLS,
|
||||
/obj/projectile/magic/resurrection = MAGICARP_SPELL_CORPSES,
|
||||
)
|
||||
|
||||
ai_controller.blackboard[BB_MAGICARP_SPELL_SPECIAL_TARGETTING] = spell_special_targetting[spell_type]
|
||||
|
||||
/// Shoot when you click away from you
|
||||
/mob/living/basic/carp/magic/RangedAttack(atom/atom_target, modifiers)
|
||||
spell.Trigger(target = atom_target)
|
||||
|
||||
/***
|
||||
* # Chaos Magicarp
|
||||
*
|
||||
* Fires a random spell (and changes colour) every time, also beefier.
|
||||
* Sometimes actually more durable than the much larger megacarp. That's magic for you.
|
||||
* They trade off for this with a tendency to fireball themselves.
|
||||
*/
|
||||
/mob/living/basic/carp/magic/chaos
|
||||
name = "chaos magicarp"
|
||||
desc = "50% carp, 100% magic, 150% horrible."
|
||||
maxHealth = 75
|
||||
health = 75
|
||||
|
||||
/mob/living/basic/carp/magic/chaos/assign_spell()
|
||||
var/datum/action/cooldown/mob_cooldown/projectile_attack/magicarp_bolt/chaos/chaos_bolt = new(src)
|
||||
chaos_bolt.permitted_projectiles = allowed_projectile_types
|
||||
chaos_bolt.Grant(src)
|
||||
spell = chaos_bolt
|
||||
ai_controller.blackboard[BB_MAGICARP_SPELL] = spell
|
||||
RegisterSignal(spell, COMSIG_ACTION_TRIGGER, PROC_REF(apply_colour))
|
||||
|
||||
/// Has a more limited spell pool but can appear from gold slime cores
|
||||
/mob/living/basic/carp/magic/xenobiology
|
||||
gold_core_spawnable = HOSTILE_SPAWN
|
||||
|
||||
/mob/living/basic/carp/magic/xenobiology/spell_list()
|
||||
return GLOB.xenobiology_magicarp_spell_types
|
||||
|
||||
/mob/living/basic/carp/magic/chaos/xenobiology
|
||||
gold_core_spawnable = HOSTILE_SPAWN
|
||||
|
||||
/mob/living/basic/carp/magic/chaos/xenobiology/spell_list()
|
||||
return GLOB.xenobiology_magicarp_spell_types
|
||||
@@ -0,0 +1,34 @@
|
||||
/**
|
||||
* ## Mega Space Carp
|
||||
*
|
||||
* A bigger space carp with more health and greater ability to smash objects.
|
||||
* Brings in some buddies when it starts fleeing as a distraction.
|
||||
* Has mildly randomised stats for some inexplicable reason, makes it somewhat more like a randomised Diablo mob.
|
||||
*/
|
||||
/mob/living/basic/carp/mega
|
||||
icon = 'icons/mob/simple/broadMobs.dmi'
|
||||
name = "Mega Space Carp"
|
||||
desc = "A ferocious, fang bearing creature that resembles a shark. This one seems especially ticked off."
|
||||
icon_state = "megacarp_greyscale"
|
||||
icon_living = "megacarp_greyscale"
|
||||
icon_dead = "megacarp_dead_greyscale"
|
||||
icon_gib = "megacarp_gib"
|
||||
health_doll_icon = "megacarp"
|
||||
maxHealth = 20
|
||||
health = 20
|
||||
pixel_x = -16
|
||||
base_pixel_x = -16
|
||||
mob_size = MOB_SIZE_LARGE
|
||||
obj_damage = 80
|
||||
cell_line = CELL_LINE_TABLE_MEGACARP
|
||||
ridable_data = /datum/component/riding/creature/megacarp
|
||||
greyscale_config = /datum/greyscale_config/carp_mega
|
||||
butcher_results = list(/obj/item/food/fishmeat/carp = 2, /obj/item/stack/sheet/animalhide/carp = 3)
|
||||
|
||||
/mob/living/basic/carp/mega/Initialize(mapload)
|
||||
. = ..()
|
||||
name = "[pick(GLOB.megacarp_first_names)] [pick(GLOB.megacarp_last_names)]"
|
||||
melee_damage_lower += rand(2, 10)
|
||||
melee_damage_upper += rand(10,20)
|
||||
maxHealth += rand(30,60)
|
||||
health = maxHealth
|
||||
Reference in New Issue
Block a user